Настройка Telegram
Hermes Agent работает в Telegram как полноценный чат-бот: отвечает на сообщения с любого устройства, расшифровывает голосовые заметки, доставляет результаты cron-задач и функционирует в группах. Под капотом — python-telegram-bot с поддержкой текста, голоса, изображений и вложений.
Быстрая настройка (дашборд и десктопное приложение)
На странице Messaging → Telegram в дашборде и в десктопном приложении есть кнопка Create with QR. Отсканируйте код или откройте ссылку в Telegram: Hermes сам создаст бота, определит ваш Telegram ID, впишет TELEGRAM_BOT_TOKEN и TELEGRAM_ALLOWED_USERS в .env вашего профиля и перезапустит шлюз. Хотите создать бота вручную — следуйте шагам ниже.
Шаг 1. Создайте бота через BotFather
Каждому Telegram-боту нужен токен API, который выдаёт @BotFather — официальный инструмент управления ботами.
- Откройте Telegram и найдите @BotFather, или перейдите по ссылке t.me/BotFather
- Отправьте
/newbot - Придумайте отображаемое имя (например, «Hermes Agent») — оно может быть любым
- Придумайте username — он должен быть уникальным и заканчиваться на
bot(например,my_hermes_bot) - BotFather пришлёт токен API в таком формате:
123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
Держите токен бота в тайне. Тот, у кого он есть, получает полный контроль над ботом. При утечке немедленно отзовите его командой /revoke в BotFather.
Шаг 2. Настройте внешний вид бота (опционально)
Эти команды BotFather улучшают пользовательский опыт:
| Команда | Назначение |
|---|---|
/setdescription | Текст «Что умеет этот бот?» перед началом чата |
/setabouttext | Короткое описание на странице профиля бота |
/setuserpic | Аватар бота |
/setcommands | Меню команд (кнопка / в чате) |
/setprivacy | Контроль видимости сообщений в группах (см. шаг 3) |
Хороший стартовый набор для /setcommands:
help - Показать справку
new - Начать новый диалог
sethome - Назначить этот чат домашним каналомИндикатор статуса онлайн/офлайн (опционально)
У Telegram-ботов нет настоящего индикатора присутствия онлайн/офлайн — зелёная точка относится к пользовательским аккаунтам, для ботов Bot API её не отдаёт. Ближайшая к этому поверхность — краткое описание бота (строка под его именем на странице профиля).
Включите status_indicator, и Hermes выставит это краткое описание в Online
при подключении шлюза и в Offline при чистом завершении:
gateway:
platforms:
telegram:
extra:
status_indicator: true
# Опционально свои строки (по умолчанию: "Online" / "Offline"):
status_online: "🟢 Online"
status_offline: "🔴 Offline"
Примечания:
- Краткое описание глобально для бота (видно всем пользователям), а не на каждый чат. Пользователи видят его на странице профиля бота, а не как живой бейдж внутри открытого чата.
- «Offline» записывается только при чистом завершении шлюза (
/stop,disconnect). После жёсткого падения остаётся последний известный статус — неизбежное ограничение индикатора на тексте профиля. - Отключено по умолчанию, поскольку меняет глобальный профиль бота.
Очередь ожидающих обновлений при холодном старте (опционально)
По умолчанию при холодном старте адаптер выбрасывает ожидающие обновления на стороне
сервера (drop_pending_updates=True при первом start_polling). Для серверов, которые
работают круглосуточно, это разумно: перезапуск означает «начать с чистого листа», а
очередь считается устаревшей. Но хостам, которые выключаются (десктоп, выключенный на
ночь), это не подходит: сообщения, отправленные, пока шлюз был офлайн, лежат в очереди
Bot API Telegram, и следующий запуск выбрасывает их ещё до того, как Hermes их увидит, —
молча, без записи в лог и без повтора.
Поставьте drop_pending_on_cold_boot: false, чтобы вместо этого получать накопившиеся
сообщения по порядку при старте:
platforms:
telegram:
extra:
drop_pending_on_cold_boot: false
Примечания:
- По умолчанию
true: пока вы сами не включите опцию, поведение прежнее. - При переподключениях наблюдателя (короткие сетевые сбои, когда процесс жив) очередь сохраняется всегда, независимо от этой настройки.
- Восстановление после конфликта по-прежнему выбрасывает ожидающие обновления, чтобы
завершить конкурирующую сессию
getUpdates, — этот путь с настройкой не связан. - После падения сохранённая очередь может повторно доставить обновление, которое упавший экземпляр успел частично обработать. Обычно этого не даёт offset Telegram, но срочные команды, отправленные за время долгого простоя, выполнятся при старте.
Параллельная обработка обновлений
Обновления из разных чатов обрабатываются параллельно, поэтому один медленный ход (долгий повтор запроса к провайдеру, большая загрузка) больше не стопорит все остальные чаты. Обновления из одного и того же чата по-прежнему идут друг за другом, в порядке прихода. Пул для разных чатов по умолчанию равен 32; недопустимое значение пишет предупреждение в лог и заменяется значением по умолчанию:
platforms:
telegram:
extra:
max_concurrent_updates: 32 # 1 restores fully sequential processing
Повторные входящие обновления
Hermes подавляет повторяющиеся значения update_id из Telegram ещё до группировки
сообщений, обработки команд и медиа, записи наблюдаемой истории группы и наблюдателей
плагинов. Область проверки — принимающий адаптер и числовой ID бота; дедупликации по
тексту или message_id нет. Настоящая правка с новым ID обновления всё равно может быть
обработана.
Это ограниченная защита в памяти, а не гарантия доставки ровно один раз:
- Адаптер помнит последние 4096 завершённых приёмов, без срока давности. Активные обновления остаются захваченными, пока не завершатся диспетчеризация и запланированные ею задачи-обработчики PTB, включая неблокирующие нативные плагины и зарегистрированные колбэки ошибок.
- Переподключение того же адаптера эту историю сохраняет. Вытеснение, замена адаптера или перезапуск процесса могут снова пропустить старое обновление. Ничего не пишется в журнал повторов на диске.
- Сорвавшаяся или отменённая подготовка снимает захват, если ничего ещё не было передано дальше. Как только обновление попало в очередь пакета/удержания, диспетчеризацию шлюза, наблюдателя или нативный плагин, последующая ошибка его уже не переоткрывает. Нативные плагины сами отвечают за свои частичные эффекты, поэтому вход в их обработчик обновления или зарегистрированный колбэк ошибок осторожно считается передачей. Собственное логирование исключений в PTB передачей не считается. Анализ зрением некэшированного статичного стикера тоже считается передачей: отмена ожидания не отменит уже отправленный запрос к вспомогательной модели. Пойманные ошибки подготовки до какой-либо передачи остаются годными для повтора; намеренный отказ — окончательный.
- Снятие захвата лишь разрешает более позднюю доставку, но не запрашивает её у Telegram. Подтверждение при опросе не зависит от завершения работы агента. Эта проверка не повторяет неудавшиеся ответы и не мешает нижестоящему компоненту самостоятельно продублировать работу.
Если подозреваете позднее повторное воспроизведение, сравните у обоих случаев
бота/профиль, чат/тему, update_id, вид обновления, message_id и фактическое время
получения. Правка может повторно использовать message_id, а время отправки сообщения —
это не время его получения.
Приоритет и лимит меню команд (опционально)
Hermes регистрирует меню команд автоматически при запуске Telegram-шлюза. Меню собирается из центрального реестра слэш-команд плюс подходящих команд плагинов/навыков, затем обрезается, чтобы Telegram надёжно принимал полезную нагрузку. Лимит по умолчанию — 60 команд: этого хватает, чтобы оставались видны все встроенные команды плюс частые команды навыков.
Если у вас есть команды навыков, плагинов или встроенные команды, которые должны оставаться видимыми в /-меню Telegram, задайте им приоритет в ~/.hermes/config.yaml:
platforms:
telegram:
extra:
command_menu:
max_commands: 60
priority_mode: prepend # prepend | append | replace
priority:
- my_plugin_command
- songsee # skill commands work here too
priority_mode определяет, как ваш список сочетается со встроенным списком приоритетов Hermes:
prepend: сначала ваши команды, затем — команды Hermes по умолчаниюappend: сначала команды Hermes по умолчанию, затем — вашиreplace: для порядка приоритета используется только ваш список
Приоритет применяется к объединённому списку кандидатов (базовые команды, команды плагинов и команды навыков) ещё до того, как сработает лимит — поэтому команда навыка с приоритетом гарантированно получит место в меню, даже если одни только базовые команды заполнили бы его целиком. Раньше навыки обрезались первыми и по алфавиту, так что навыки в конце алфавита не попадали в меню независимо от priority.
Telegram допускает до 100 BotCommands, но крупная полезная нагрузка команд может не пройти. Hermes по умолчанию берёт 60 для надёжности и ограничивает заданные значения диапазоном 1..100; полный список команд — через /commands.
Инлайн-подбор команд: поиск по всем командам (без лимита)
Меню / ограничено лимитом, а вот инлайн-режим Telegram — нет. После включения наберите @yourbotname, а затем поисковый запрос в любом чате — откроется живой поиск по всем командам Hermes и установленным навыкам: результаты пересчитываются на каждое нажатие клавиши и разбиваются на страницы, так что ничего не обрезается:
@yourbotname plan → tap the /plan result to send it
@yourbotname plan migrate auth to OIDC → sends /plan migrate auth to OIDC
@yourbotname pdf → finds skills matching "pdf" by name or description
Первое слово фильтрует каталог, всё, что после него, передаётся в отправляемую команду как аргумент. Нажатие на результат отправляет команду обычным сообщением от вашего имени, поэтому она проходит через стандартный путь команд (сообщения с командным префиксом доходят до бота даже при включённом режиме конфиденциальности).
Разовая настройка: инлайн-режим по умолчанию выключен для любого Telegram-бота. Включите его в @BotFather командой /setinline (выберите бота, задайте любой текст-заглушку, например Search commands and skills...). Пока это не сделано, Telegram вообще не доставляет инлайн-запросы, и подборщик бездействует.
Результаты выдаются только пользователям, прошедшим список разрешений вашего шлюза — неавторизованные пользователи получают пустой список, так что каталог установленных навыков не раскрывается посторонним (инлайн-запросы можно отправить из любого чата, даже того, где бота нет).
Шаг 3. Режим конфиденциальности в группах (важно)
По умолчанию у Telegram-ботов включён режим конфиденциальности — это самая частая причина путаницы при работе в группах.
С включённым режимом бот видит только:
- Сообщения, начинающиеся с
/команды - Ответы напрямую на сообщения бота
- Системные сообщения (вход/выход участников, закреплённые сообщения и т. п.)
- Сообщения в каналах, где бот является администратором
С выключенным режимом бот получает каждое сообщение в группе.
Как отключить режим конфиденциальности
- Напишите @BotFather
- Отправьте
/mybots - Выберите своего бота
- Перейдите в Bot Settings → Group Privacy → Turn off
Обязательно удалите и снова добавьте бота в группу после смены настройки конфиденциальности. Telegram кэширует это состояние в момент вступления бота в группу — изменение не подхватится автоматически.
Альтернатива отключению: назначьте бота администратором группы. Боты-администраторы всегда получают все сообщения, независимо от настройки конфиденциальности.
Наблюдение за чатом без автоответа
Чтобы бот видел обычные сообщения группы, но реагировал только по вызову (как в OpenClaw/Yuanbao), настройте такую конфигурацию:
telegram:
allowed_chats:
- "-1001234567890"
group_allowed_chats:
- "-1001234567890"
require_mention: true
observe_unmentioned_group_messages: true
В этом режиме обычные сообщения из разрешённых чатов добавляются в общую сессию как контекст наблюдения, но агент не запускается. Последующее упоминание @botname, ответ боту или настроенный wake-паттерн в том же чате может использовать накопленный контекст. Инициирующее сообщение помечается [nickname|user_id], а модель через per-turn safety промпт воспринимает наблюдённые строки именно как контекст, а не как обращённые к боту инструкции.
Эквивалентные переменные окружения:
TELEGRAM_ALLOWED_CHATS=-1001234567890
TELEGRAM_GROUP_ALLOWED_CHATS=-1001234567890
TELEGRAM_OBSERVE_UNMENTIONED_GROUP_MESSAGES=true
Для работы этого режима Telegram должен доставлять боту обычные сообщения группы — отключите режим конфиденциальности или назначьте бота администратором, как описано выше.
Шаг 4. Узнайте свой Telegram User ID
Hermes использует числовые Telegram User ID для контроля доступа. Ваш ID — не username, а число вида 123456789.
Способ 1 (рекомендуется): Напишите @userinfobot — он мгновенно пришлёт ваш ID.
Способ 2: Напишите @get_id_bot — ещё один надёжный вариант.
Запишите этот номер: он понадобится в следующем шаге.
Шаг 5. Настройте Hermes
Вариант А. Интерактивная настройка (рекомендуется)
hermes gateway setup
Выберите Telegram в меню. Мастер запросит токен бота и список разрешённых пользователей, затем сам запишет конфигурацию.
Вариант Б. Ручная настройка
Добавьте в ~/.hermes/.env:
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
TELEGRAM_ALLOWED_USERS=123456789 # несколько ID через запятую
Запустите шлюз
hermes gateway
Бот выйдет в онлайн за несколько секунд. Напишите ему в Telegram, чтобы убедиться.
Отправка файлов из Docker-контейнеров
Если терминальный бэкенд — docker, важно помнить: вложения Telegram отправляет процесс шлюза, а не контейнер. Значит, путь в MEDIA:/... должен быть читаемым на хосте, где запущен шлюз.
Типичная ошибка:
- агент записал файл в Docker по пути
/workspace/report.txt - модель вернула
MEDIA:/workspace/report.txt - Telegram не доставил вложение, потому что
/workspace/report.txtсуществует только внутри контейнера
Рекомендуемый подход:
terminal:
backend: docker
docker_volumes:
- "/home/user/.hermes/cache/documents:/output"
Тогда:
- агент пишет файлы в Docker по пути
/output/... - в
MEDIA:указываете путь на хосте:MEDIA:/home/user/.hermes/cache/documents/report.txt
Если секция docker_volumes: уже есть, просто добавьте новый маунт в тот же список. Дублирующиеся YAML-ключи молча перезаписывают предыдущие.
Поддерживаемые расширения в MEDIA:
Шлюз извлекает теги MEDIA:/путь/к/файлу из ответов агента и доставляет файл как нативное вложение платформы:
| Категория | Расширения |
|---|---|
| Изображения | png, jpg, jpeg, gif, webp, bmp, tiff, svg |
| Аудио | mp3, wav, ogg, m4a, opus, flac, aac |
| Видео | mp4, mov, webm, mkv, avi |
| Документы | pdf, txt, md, csv, json, xml, html, yaml, yml, log |
| Office | docx, xlsx, pptx, odt, ods, odp |
| Архивы | zip, rar, 7z, tar, gz, bz2 |
| Книги / пакеты | epub, apk, ipa |
На платформах с нативной поддержкой (Telegram, Discord, Signal, Slack, WhatsApp, Feishu, Matrix и др.) файл приходит как вложение; там, где нативного способа нет, — как ссылка или текстовый маркер. Жирные категории добавлены в последних релизах — если раньше модель возвращала просто путь /path/to/report.docx, переключайтесь на MEDIA:/path/to/report.docx для нативной доставки.
Режим вебхука
По умолчанию Hermes соединяется с Telegram через long polling — шлюз сам запрашивает новые обновления у серверов Telegram. Для локальных и постоянно включённых машин это работает хорошо.
Для облачных деплоев (Fly.io, Railway, Render и т. п.) экономнее вебхук: эти платформы умеют пробуждать спящую машину по входящему HTTP-запросу, но не по исходящему. Опрашивающий бот не может перейти в спящий режим. Вебхук переворачивает направление — Telegram сам отправляет обновления на URL вашего бота, и машина может спать между сообщениями.
| Polling (по умолчанию) | Вебхук | |
|---|---|---|
| Направление | Шлюз → Telegram (исходящее) | Telegram → Шлюз (входящее) |
| Лучше для | Локальных и постоянно включённых серверов | Облачных платформ с auto-wake |
| Настройка | Не нужна | Задайте TELEGRAM_WEBHOOK_URL |
| Стоимость простоя | Машина должна работать | Машина может спать |
Конфигурация
Добавьте в ~/.hermes/.env:
TELEGRAM_WEBHOOK_URL=https://my-app.fly.dev/telegram
TELEGRAM_WEBHOOK_SECRET="$(openssl rand -hex 32)" # обязательно
# TELEGRAM_WEBHOOK_PORT=8443 # опционально, по умолчанию 8443
| Переменная | Обязательна | Описание |
|---|---|---|
TELEGRAM_WEBHOOK_URL | Да | Публичный HTTPS-адрес, куда Telegram будет слать обновления. Путь URL извлекается автоматически (например, /telegram из примера выше). |
TELEGRAM_WEBHOOK_SECRET | Да (если задан TELEGRAM_WEBHOOK_URL) | Секретный токен, который Telegram вставляет в каждый вебхук-запрос. Без него шлюз не запустится — см. GHSA-3vpc-7q5r-276h. Генерируйте через openssl rand -hex 32. |
TELEGRAM_WEBHOOK_PORT | Нет | Локальный порт, на котором слушает вебхук-сервер (по умолчанию 8443). |
Если TELEGRAM_WEBHOOK_URL задан, шлюз запускает HTTP-сервер вместо polling. Без него — polling, поведение прежнее.
Пример деплоя в облако (Fly.io)
- Добавьте переменные в секреты Fly.io:
fly secrets set TELEGRAM_WEBHOOK_URL=https://my-app.fly.dev/telegram
fly secrets set TELEGRAM_WEBHOOK_SECRET=$(openssl rand -hex 32)
- Откройте порт вебхука в
fly.toml:
[[services]]
internal_port = 8443
protocol = "tcp"
[[services.ports]]
handlers = ["tls", "http"]
port = 443
- Задеплойте:
fly deploy
В логах шлюза должна появиться строка: [telegram] Connected to Telegram (webhook mode).
Поддержка прокси
Если Telegram API заблокирован в вашей сети или трафик нужно пустить через прокси, задайте Telegram-специфичный URL прокси. Он имеет приоритет над общими переменными HTTPS_PROXY / HTTP_PROXY.
Вариант 1: config.yaml (рекомендуется)
telegram:
proxy_url: "socks5://127.0.0.1:1080"
Вариант 2: переменная окружения
TELEGRAM_PROXY=socks5://127.0.0.1:1080
Поддерживаемые схемы: http://, https://, socks5://.
Прокси применяется к основному соединению с Telegram и к резервному IP-транспорту. Если Telegram-специфичный прокси не задан, шлюз обращается к HTTPS_PROXY / HTTP_PROXY / ALL_PROXY (или к системному автоопределению прокси на macOS).
Если путь обнаружения запасных IP на вашем хосте работает нестабильно, задайте HERMES_TELEGRAM_DISABLE_FALLBACK_IPS=true, чтобы холодное подключение всегда шло через обычный путь api.telegram.org. Также можно ограничить время обнаружения запасных IP через DNS-over-HTTPS переменной HERMES_TELEGRAM_FALLBACK_DISCOVERY_TIMEOUT (в секундах); значение по умолчанию — 5.
Домашний канал
Команда /sethome в любом чате Telegram (личном или групповом) назначает его домашним каналом — именно туда cron-задачи будут доставлять результаты.
Можно задать вручную в ~/.hermes/.env:
TELEGRAM_HOME_CHANNEL=-1001234567890
TELEGRAM_HOME_CHANNEL_NAME="Мои заметки"
ID групповых чатов отрицательные (например, -1001234567890). ID личного диалога совпадает с вашим User ID.
Cron-доставка в режиме тем
Если у вас включён режим тем в боте, cron-сообщения в корневом чате попадают в системное лобби — ответить там нельзя, и вы увидите уведомление «main chat is reserved for system commands». Создайте отдельную тему форума (например, Cron) и задайте:
TELEGRAM_CRON_THREAD_ID=<id_темы>
TELEGRAM_CRON_THREAD_ID перекрывает TELEGRAM_HOME_CHANNEL_THREAD_ID только для cron-доставки. Ответы в этой теме продолжают её существующую сессию.
Голосовые сообщения
Входящий голос (Speech-to-Text)
Голосовые сообщения в Telegram автоматически расшифровываются STT-провайдером Hermes и добавляются в диалог как текст.
localиспользуетfaster-whisperна машине с Hermes — ключ API не нуженgroqиспользует Groq Whisper, требуетGROQ_API_KEYopenaiиспользует OpenAI Whisper, требуетVOICE_TOOLS_OPENAI_KEY
Отключить STT и отдать аудио агенту напрямую
Если нужно, чтобы агент сам обработал аудио — для диаризации, кастомного STT или архивирования — задайте stt.enabled: false в ~/.hermes/config.yaml:
stt:
enabled: false
При отключённом STT шлюз всё равно скачивает голосовое вложение в аудиокэш Hermes, но не расшифровывает. Агент получает сообщение вида:
[The user sent a voice message: /home/<user>/.hermes/cache/audio/<hash>.ogg]
Ваши инструменты или навыки могут напрямую читать этот путь — например, передать его в локальный пайплайн диаризации, более полнофункциональную модель транскрипции или загрузить в долгосрочное хранилище. Расширение файла соответствует формату, в котором Telegram доставил запись (.ogg для голосовых заметок, .mp3/.m4a для аудиовложений).
Это удобно в связке с локальным Bot API-сервером, который поднимает ограничение Telegram с 20 МБ до 2 ГБ, — полезно для длинных записей.
Исходящий голос (Text-to-Speech)
Когда агент генерирует аудио через TTS, оно доставляется в Telegram как нативные голосовые пузырьки — круглые, воспроизводимые прямо в чате.
- OpenAI и ElevenLabs генерируют Opus нативно — дополнительной настройки не нужно
- Edge TTS (бесплатный провайдер по умолчанию) отдаёт MP3 и требует ffmpeg для конвертации в Opus:
# Ubuntu/Debian
sudo apt install ffmpeg
# macOS
brew install ffmpeg
Без ffmpeg аудио от Edge TTS приходит как обычный аудиофайл (воспроизводится, но прямоугольным плеером, а не голосовым пузырьком).
Провайдер TTS настраивается в config.yaml под ключом tts.provider.
Крупные файлы (>20 МБ) через локальный Bot API-сервер
Публичный Bot API Telegram ограничивает загрузку через getFile файлами до 20 МБ — любые голосовые заметки, аудио, видео или документы крупнее этого предела Hermes молча отклоняет с ответом «слишком большой файл». Официальный обходной путь — запустить локальный telegram-bot-api демон: тот же серверный код, что использует Telegram, но работает в вашей сети. Локальный сервер поднимает ограничение до 2 ГБ, и Hermes автоматически снимает свой внутренний лимит, увидев кастомный base_url.
Это открывает сценарии вроде:
- Отправки длинных голосовых заметок (45-минутные совещания, подкасты) боту
- Загрузки крупных видео для обработки vision-инструментами
- Архивирования сырого аудио для офлайн-пайплайнов диаризации или обучения
Шаг 1. Получите MTProto-учётные данные
Локальный сервер общается с Telegram напрямую через MTProto (не через публичный Bot API), поэтому ему нужны MTProto-учётные данные:
- Зайдите на my.telegram.org/apps и войдите под своим аккаунтом.
- Создайте новое приложение (название и описание — любые).
- Скопируйте
api_idиapi_hash— оба обязательны.
Шаг 2. Запустите telegram-bot-api сервер
Проще всего использовать поддерживаемый сообществом Docker-образ aiogram/telegram-bot-api. Минимальный docker-compose.yaml (флаг --local поднимает лимиты):
services:
tg-bot-api:
image: aiogram/telegram-bot-api:latest
container_name: tg-bot-api
restart: unless-stopped
ports:
- "127.0.0.1:8081:8081" # привязываем только к loopback; см. замечание о безопасности
environment:
TELEGRAM_API_ID: "12345" # ваш api_id из шага 1
TELEGRAM_API_HASH: "abcdef..." # ваш api_hash из шага 1
TELEGRAM_LOCAL: "1" # включает --local режим (20 МБ → 2 ГБ)
volumes:
- ./tg-bot-api-data:/var/lib/telegram-bot-api
Запустите:
docker compose up -d tg-bot-api
docker logs --tail 20 tg-bot-api
Локальный Bot API-сервер принимает токен бота прямо в пути URL (/bot<TOKEN>/getMe) без какой-либо аутентификации. Любой, кто имеет доступ к порту, получает полный контроль над ботом — читает все доступные ему сообщения, отправляет сообщения от его имени и т. д. Привяжите контейнер к 127.0.0.1 и/или вынесите его за реверс-прокси в приватной сети. Никогда не выставляйте порт 8081 в публичный интернет.
Шаг 3. Выведите бота из публичного API (один раз)
Бот может быть активен только на одном Bot API-сервере одновременно. Если он уже работал через api.telegram.org (почти наверняка так и есть), сначала явно выйдите там:
curl "https://api.telegram.org/bot<ВАШ_ТОКЕН>/logOut"
# ожидаемый ответ: {"ok":true,"result":true}
Это разовая миграция — повторять при каждом перезапуске не нужно. Telegram перенаправит сообщения, пришедшие после logOut, через новый сервер.
Проверьте, что локальный сервер работает:
curl "http://127.0.0.1:8081/bot<ВАШ_ТОКЕН>/getMe"
# ожидаемый ответ: {"ok":true,"result":{"id":...,"is_bot":true,...}}
Шаг 4. Направьте Hermes на локальный сервер
Добавьте URL-адреса в ~/.hermes/config.yaml под platforms.telegram.extra:
platforms:
telegram:
extra:
base_url: "http://127.0.0.1:8081/bot"
base_file_url: "http://127.0.0.1:8081/file/bot"
local_mode: true # см. шаг 5 — задавайте, только если директория данных сервера
# доступна процессу Hermes
platforms.telegram.extra, а не telegram.extra
Сейчас только форма platforms.<name>.extra глубоко мержится в конфигурацию платформы. Ключи в верхнеуровневом блоке telegram.extra молча отбрасываются.
Когда base_url задан, Hermes:
- Строит клиент python-telegram-bot против локального сервера
- Автоматически поднимает внутренний лимит документов/аудио с 20 МБ до 2 ГБ
- Показывает активный лимит в сообщении об ошибке «слишком большой файл» (
Maximum: 2048 MB.), чтобы было понятно, в каком режиме вы работаете
Перезапустите шлюз и проверьте подтверждающую строку в логах:
hermes gateway restart
grep -E "Using custom Telegram base_url|Using Telegram local_mode" ~/.hermes/logs/gateway.log | tail
Шаг 5. local_mode — доступ к файлам на диске
Локальный сервер может отдавать файлы двумя способами:
- Без
--local(по умолчанию): файлы отдаются через HTTP по пути/file/bot<TOKEN>/<path>, как в публичном Bot API. Ограничение 20 МБ остаётся. Полезно только как сетевой обходной путь (например, когдаapi.telegram.orgнедоступен, но можно хостить локально); для снятия лимита по размеру не подходит. - С
--local(задаётся черезTELEGRAM_LOCAL=1выше): файлы пишутся в файловую систему сервера, а ответgetFileвозвращает абсолютный путь вместо HTTP URL. Ограничение 20 МБ снято. Hermes должен читать байты с диска, а не по HTTP.
Чтобы чтение с диска работало, задайте local_mode: true в конфиге выше и убедитесь, что процесс Hermes может читать путь, который возвращает сервер. Два сценария:
- Одна машина — telegram-bot-api и Hermes на одном хосте. Смонтируйте том данных в директорию, читаемую Hermes (например,
/var/lib/telegram-bot-api), и проверьте права доступа. Контейнер сбрасывает привилегии до внутреннего пользователяtelegram-bot-api(UID зависит от образа); проще всего добавить в compose-сервисuser: "<UID>:<GID>", чтобы файлы принадлежали уже существующему UID Hermes. - Разные машины — Bot API-сервер на одном хосте (NAS, отдельная VM), Hermes на другом. Директория данных сервера должна быть расшарена на машину с Hermes по тому же абсолютному пути, который сервер указывает (обычно
/var/lib/telegram-bot-api). NFS хорошо подходит; CIFS/SMB с параметром маунтаuid=удобнее, если не хочется разбираться с несовпадением UID на уровне файловой системы.
Если local_mode: true задан, но Hermes не может выполнить stat по возвращённому пути (права или неверный маунт), python-telegram-bot молча откатывается к HTTP getFile на локальный сервер — а тот в режиме --local отвечает 404 Not Found. Симптом в gateway.log:
[Telegram] Failed to cache voice: Not Found
telegram.error.InvalidToken: Not Found
Если видите это — поднятие лимита работает, а расшаривание файлов — нет. Проверьте ls -la /var/lib/telegram-bot-api/<TOKEN>/voice/ с хоста Hermes под пользователем, от которого запущен шлюз, и убедитесь, что один файл читается через cat без ошибки прав.
Шаг 6. Протестируйте
Отправьте боту голосовую заметку или аудиофайл крупнее 20 МБ. Следите за логами шлюза:
tail -f ~/.hermes/logs/gateway.log | grep -iE "telegram|cache"
Должна появиться строка [Telegram] Cached user voice at /home/<user>/.hermes/cache/audio/... и никаких отклонений «слишком большой файл». В связке с stt.enabled: false (описано выше) путь к исходному аудиофайлу попадает в входящее сообщение агента для дальнейшей обработки.
Работа в групповых чатах
Hermes в групповых чатах Telegram работает с рядом особенностей:
- Режим конфиденциальности определяет, какие сообщения видит бот (см. шаг 3)
TELEGRAM_ALLOWED_USERSдействует и в группах — только авторизованные пользователи могут вызвать ботаtelegram.require_mention: trueне даёт боту реагировать на обычный групповой чат- При
telegram.require_mention: trueсообщения в группах принимаются, если это:- ответ на одно из сообщений бота
- упоминание
@botusername /command@botusername(формат команды меню с именем бота)- совпадение с одним из настроенных wake-паттернов в
telegram.mention_patterns
- В группах с несколькими Hermes-ботами
telegram.exclusive_bot_mentionsделает маршрутизацию предсказуемой. Если сообщение явно упоминает одного или нескольких Telegram-ботов, обрабатывают его только упомянутые профили; остальные Hermes-боты игнорируют его до проверки ответов и wake-слов. По умолчанию включено. - Переименование
@usernameбота в BotFather подхватывается автоматически — Hermes следует за новым хендлом для маршрутизации по упоминаниям без перезапуска шлюза. Поддерживаются и коллекционные username (Fragment), не заканчивающиеся наbot. telegram.ignored_threadsзаставляет Hermes молчать в определённых темах форума, даже если группа разрешает свободные ответы или ответы по упоминанию- Если
telegram.require_mentionне задан илиfalse, Hermes ведёт себя по-старому: отвечает на все видимые сообщения группы
Несколько Hermes-ботов в одной группе
Если у вас несколько профилей Hermes в одной группе Telegram, создайте отдельный токен на каждый профиль и запустите по одному шлюзу. Не переиспользуйте один токен в нескольких работающих шлюзах — Telegram отклонит конкурирующий polling для одного и того же токена.
Рекомендуемая конфигурация для группы:
telegram:
require_mention: true
exclusive_bot_mentions: true
mention_patterns: []
С такой настройкой сообщение вида @research_bot @ops_bot summarize this обработают только research_bot и ops_bot. Остальные Hermes-боты в группе промолчат, даже если сообщение — ответ на одно из их предыдущих или совпадает с общим wake-словом.
Два Hermes-бота, отвечающие на цитаты друг друга, при TELEGRAM_ALLOW_BOTS=all всё ещё могут зациклиться навсегда: ответ боту гейт require_mention проходит всегда. Закрывает эту лазейку telegram.bots_require_mention: true (переменная TELEGRAM_BOTS_REQUIRE_MENTION): сообщение от другого бота вызовет ответ только при явном @упоминании этого бота, а ответы людей продолжают работать как раньше.
Защита от петель «бот — бот» вдобавок считает сообщения в каждом чате, куда допущены сообщения ботов (TELEGRAM_ALLOW_BOTS в mentions или all). Как только за 5 минут в одном чате набирается 20 сообщений от ботов, дальнейшие сообщения ботов в этом чате отбрасываются на 10 минут, а в лог пишется одно предупреждение; сообщения людей не считаются и не отбрасываются никогда. Настройки живут в config.yaml:
gateway:
bot_loop_guard:
enabled: true # false отключает защиту
max_events: 20 # сообщений ботов на чат за окно
window_seconds: 300
cooldown_seconds: 600
Легитимный многословный бот, публикующий больше 20 сообщений в один чат за 5 минут, тоже споткнётся о защиту — поднимите max_events для этого шлюза.
Текст групповой переписки и подписи к медиа сохраняют все упоминания, когда в сообщении названы и другие участники (@research_bot , @ops_bot are you both listening? дойдёт до research_bot дословно); когда же адресат один, собственный хэндл бота по-прежнему вырезается, чтобы работали короткие ответы вида @hermes_bot 2. В контекст канала для групповых ходов заодно кладётся собственный юзернейм бота в Telegram — так модель понимает, какие из сохранённых упоминаний адресованы ей. Слэш-команды по-прежнему проходят обычную чистку триггера команды.
Задавайте exclusive_bot_mentions: false только для устаревших групп, где явные упоминания не должны перекрывать ответы и wake-триггеры.
Для нескольких профилей запускайте шлюз отдельной командой на каждый:
# профиль по умолчанию
hermes gateway start
hermes gateway status
hermes gateway stop
# именованные профили
hermes -p research gateway start
hermes -p research gateway status
hermes -p research gateway stop
Для небольшого фиксированного набора профилей удобен shell-цикл или скрипт, который вызывает hermes gateway <action> для дефолтного профиля и hermes -p <profile> gateway <action> для каждого именованного. Это надёжнее, чем надеяться, что одна команда управляет всеми профилями на любом менеджере служб.
Проблемы в группах: работает в ЛС, но молчит в группе
Если бот отвечает в личных сообщениях, но игнорирует группу, проверьте по порядку:
- Доставка Telegram: отключите режим конфиденциальности BotFather, назначьте бота администратором или явно упомяните его. Hermes не может ответить на сообщения, которые Telegram не доставил.
- Повторное вступление: после смены настройки конфиденциальности в BotFather удалите бота из группы и добавьте снова. Telegram может сохранять старое поведение для текущих участников.
- Авторизация Hermes: убедитесь, что отправитель есть в
TELEGRAM_ALLOWED_USERSилиTELEGRAM_GROUP_ALLOWED_USERS, либо группа разрешена черезTELEGRAM_GROUP_ALLOWED_CHATS. - Фильтры упоминаний: при
telegram.require_mention: trueобычный групповой чат игнорируется, если это не команда-слэш, ответ боту, упоминание@botusernameили совпадение сmention_patterns. - Маршрутизация между ботами: если в группе несколько ботов, убедитесь, что у каждого профиля Hermes уникальный токен и включён
exclusive_bot_mentions(если не нужно унаследованное поведение с общими триггерами).
Отрицательные ID чатов — норма для групп и супергрупп Telegram. При чат-скопированной авторизации указывайте эти ID в TELEGRAM_GROUP_ALLOWED_CHATS, а не в списке пользователей.
Пример конфигурации триггеров для группы
Добавьте в ~/.hermes/config.yaml:
telegram:
require_mention: true
exclusive_bot_mentions: true
mention_patterns:
- "^\\s*chompy\\b"
ignored_threads:
- 31
- "42"
Здесь разрешены все стандартные триггеры плюс сообщения, начинающиеся с chompy, даже без @mention. Сообщения в темах 31 и 42 всегда игнорируются до проверки упоминаний и свободных ответов.
Замечания по mention_patterns
- Паттерны используют синтаксис регулярных выражений Python
- Совпадение нечувствительно к регистру
- Паттерны проверяются для текстовых сообщений и подписей к медиафайлам
- Невалидные паттерны пропускаются с предупреждением в логах шлюза, а не крашат бота
- Чтобы паттерн срабатывал только в начале сообщения, добавьте
^
Личные темы чата (Bot API 9.4)
Bot API Telegram 9.4 (февраль 2026) добавил Personal Chat Topics — боты могут создавать темы форума прямо в личных диалогах (DM), без супергруппы. Это позволяет вести несколько изолированных рабочих пространств в одном вашем диалоге с Hermes.
Сценарий
Если вы ведёте несколько долгих проектов, темы держат контекст раздельно:
- Тема «Сайт» — работа с продакшн-веб-сервисом
- Тема «Исследования» — обзор литературы и разбор статей
- Тема «Общее» — разные задачи и быстрые вопросы
У каждой темы своя история диалога, память и контекстное окно — полная изоляция.
Конфигурация
Прежде чем добавлять темы в конфиг, владелец бота должен включить Threaded Mode для бота в @BotFather:
- Откройте Mini App BotFather (найдите
botfatherв поиске Telegram и нажмите Open в результате поиска — классическое текстовое меню/mybotsэтой настройки не показывает) - Перейдите в My bots → ваш бот → Bot Settings → Threads Settings
- Включите Threaded Mode
В самом личном чате переключателя «Topics» нет: личный диалог с ботом — не группа, так что переключатель форума для групп, описанный в некоторых старых руководствах, здесь не применяется. Без Threaded Mode Hermes при запуске выведет в лог The chat is not a forum и пропустит создание тем. Те же шаги подробнее — в разделе Предварительные условия ниже.
Добавьте темы в ~/.hermes/config.yaml под platforms.telegram.extra.dm_topics:
platforms:
telegram:
extra:
dm_topics:
- chat_id: 123456789 # ваш Telegram User ID
topics:
- name: Общее
icon_color: 7322096
- name: Сайт
icon_color: 9367192
- name: Исследования
icon_color: 16766590
skill: arxiv # автозагрузка навыка в этой теме
Поля:
| Поле | Обязательно | Описание |
|---|---|---|
name | Да | Отображаемое имя темы |
icon_color | Нет | Код цвета иконки Telegram (целое число) |
icon_custom_emoji_id | Нет | ID кастомного эмодзи для иконки темы |
skill | Нет | Навык для автозагрузки в новых сессиях этой темы |
thread_id | Нет | Заполняется автоматически после создания темы — не задавайте вручную |
Как это работает
- При запуске шлюза Hermes вызывает
createForumTopicдля каждой темы безthread_id thread_idсохраняется обратно вconfig.yamlавтоматически — последующие перезапуски пропускают вызов API- Каждая тема привязана к изолированному ключу сессии:
agent:main:telegram:dm:{chat_id}:{thread_id} - Сообщения в каждой теме имеют собственную историю, сброс памяти и контекстное окно
Обработка корневого DM
По умолчанию сообщения в корневом DM (вне тем) обрабатываются обычным образом. Задайте ignore_root_dm: true, чтобы превратить корневой DM в лобби — обычные сообщения молча игнорируются для пользователей с настроенными темами, системные команды (/start, /help, /status и т. п.) по-прежнему работают.
platforms:
telegram:
extra:
ignore_root_dm: true
dm_topics:
- chat_id: 123456789
topics:
- name: Общее
Проверка выполняется на уровне чата: затрагиваются только пользователи с хотя бы одной записью в dm_topics. Те, у кого тем нет, работают как прежде.
Привязка навыка к теме
Темы с полем skill автоматически загружают этот навык в начале каждой новой сессии — как если бы вы сами набрали /skill-name в чате. Содержимое навыка добавляется в первое сообщение, и все последующие видят его в истории диалога.
Например, тема с skill: arxiv будет загружать навык arxiv при каждом сбросе сессии (после явного /new или /reset).
Темы, созданные вне конфига (например, прямым вызовом Telegram API), обнаруживаются автоматически при получении служебного сообщения forum_topic_created. Темы можно также добавлять в конфиг при работающем шлюзе — они будут подхвачены при следующем кэш-промахе.
Мультисессионный режим DM (/topic)
ChatGPT-подобный режим множества параллельных диалогов: один бот, много независимых разговоров. В отличие от оператор-настраиваемых extra.dm_topics выше, этот режим управляется самим пользователем: никакого конфига, никаких заранее заданных имён тем. Пользователь включает режим командой /topic, затем нажимает кнопку + в Telegram и создаёт сколько угодно тем — каждая становится отдельной сессией Hermes.
Подкоманды /topic
| Форма | Контекст | Действие |
|---|---|---|
/topic | Корневой DM, ещё не включён | Проверяет возможности BotFather, включает мультисессионный режим, создаёт закреплённую тему System |
/topic | Корневой DM, уже включён | Показывает статус: доступные несвязанные сессии для восстановления |
/topic | Внутри темы | Показывает привязку сессии текущей темы |
/topic help | Любой | Встроенная справка |
/topic off | Корневой DM | Отключает мультисессионный режим и сбрасывает привязки тем для этого чата |
/topic <session-id> | Внутри темы | Восстанавливает предыдущую сессию Hermes в текущей теме |
Запустить /topic могут только авторизованные пользователи (через TELEGRAM_ALLOWED_USERS или конфиг платформы). Неавторизованному отправляется отказ вместо активации.
Сравнение DM Topics и мультисессионного DM-режима
extra.dm_topics (через конфиг) | /topic (управляется пользователем) | |
|---|---|---|
| Кто включает | Оператор в config.yaml | Пользователь командой /topic |
| Список тем | Фиксированный, задан в конфиге | Пользователь создаёт и удаляет темы свободно |
| Имена тем | Задаёт оператор | Задаёт пользователь; автоматически переименовываются под название сессии Hermes |
| Корневой DM | Обычный чат (лобби при ignore_root_dm: true) | Становится системным лобби (обычные сообщения отклоняются) |
| Основной сценарий | Постоянные рабочие пространства с опциональной привязкой навыка | Произвольные параллельные сессии |
| Хранилище | extra.dm_topics в конфиге | Таблицы telegram_dm_topic_mode и telegram_dm_topic_bindings в SQLite |
Оба режима могут работать на одном боте одновременно: /topic активируется из вашего DM, а extra.dm_topics продолжает управлять оператор-объявленными темами в других чатах.
Предварительные условия
В @BotFather откройте своего бота → Bot Settings → Threads Settings:
- Включите Threaded Mode (
has_topics_enabled) - Не отключайте разрешение пользователям создавать темы (
allows_users_to_create_topics)
При первом запуске /topic Hermes вызывает getMe и проверяет оба флага. Если хотя бы один выключен — присылает скриншот с экраном настроек BotFather и объясняет, что переключить. Активация не произойдёт, пока условия не выполнены.
Процесс активации
В корневом DM отправьте:
/topic
Hermes:
- Проверит
getMe().has_topics_enabledиallows_users_to_create_topics - Если оба флага включены — активирует мультисессионный режим для этого DM
- Создаст и закрепит тему System для статуса и команд (по возможности)
- Пришлёт список предыдущих несвязанных Telegram-сессий, которые можно восстановить
После активации корневой DM превращается в лобби: обычные промпты отклоняются с подсказкой перейти в All Messages. Системные команды (/status, /sessions, /usage, /help и т. п.) в корне по-прежнему работают.
Создание новой темы (для пользователя)
- Откройте DM с ботом в Telegram
- Нажмите All Messages вверху интерфейса бота и отправьте любое сообщение
- Telegram создаст новую тему для этого сообщения
- Hermes ответит внутри темы — она становится отдельной сессией
У каждой темы своя история диалога, состояние модели, выполнение инструментов и ID сессии. Ключ изоляции: agent:main:telegram:dm:{chat_id}:{thread_id} — тот же, что у конфиг-управляемых DM-тем.
Автоматическое переименование тем
Когда Hermes генерирует заголовок сессии для темы (через пайплайн авто-заголовков, после первого обмена), тема Telegram переименовывается соответственно — «Новая тема» превращается, например, в «План миграции базы данных». Переименование выполняется по возможности: ошибки логируются, но не ломают сессию.
Чтобы отключить это и сохранять имена тем нетронутыми:
gateway:
platforms:
telegram:
extra:
disable_topic_auto_rename: true
При включённом флаге Hermes всё равно генерирует внутренний заголовок сессии (виден в hermes sessions, TUI и т. д.), но никогда не редактирует имя темы в Telegram. Удобно, когда вы организуете темы вручную через BotFather Threaded Mode и не хотите, чтобы первый же ответ перезаписывал название.
/new внутри темы
Сбрасывает сессию текущей темы (новый ID сессии, чистая история) без затрагивания других тем. Hermes напоминает, что для параллельной работы обычно проще создать ещё одну тему через All Messages.
Восстановление предыдущей сессии
Внутри темы отправьте:
/topic <session-id>
Текущая тема привяжется к существующей сессии Hermes вместо новой. Полезно для продолжения разговора, начатого до включения режима тем. Ограничения:
- Целевая сессия должна принадлежать тому же пользователю Telegram
- Целевая сессия не должна быть уже привязана к другой теме
Hermes подтверждает привязку заголовком сессии и воспроизводит последнее сообщение ассистента для контекста.
Чтобы узнать ID доступных сессий, отправьте /topic (без аргументов) в корневом DM — Hermes выведет несвязанные Telegram-сессии пользователя.
/topic внутри темы (без аргумента)
Показывает привязку текущей темы: заголовок сессии, ID сессии и подсказки по /new и созданию новой темы.
Под капотом
- Активация сохраняется в
telegram_dm_topic_mode(profile_name, chat_id, user_id, enabled, ...)вstate.db. Первичный ключ —(profile_name, chat_id), поэтому мультиплексные боты и боты с маршрутизацией по профилям, делящие однуstate.db, не затирают записи друг друга, когда один и тот же пользователь Telegram пишет нескольким ботам (в личкеchat_id— это идентификатор пользователя, и он у всех ботов одинаковый) - Каждая привязка темы — в
telegram_dm_topic_bindings(profile_name, chat_id, thread_id, session_id, ...)с первичным ключом(profile_name, chat_id, thread_id)иON DELETE CASCADEпоsession_id: удаление сессии автоматически сбрасывает привязку - SQLite-миграция для режима тем — opt-in: запускается при первом вызове
/topic, никогда при старте шлюза. До вызова/topicstate.dbне меняется. Схема v3 добавляетprofile_name; старые строки переезжают только в пространство имёнdefault - Каждое входящее DM-сообщение ищет привязку
(profile_name, chat_id, thread_id)по маршрутизированному профилю (source.profile, а не по глобально активному профилю процесса). Если найдена — маршрутизирует сообщение в привязанную сессию черезSessionStore.switch_session(), сохраняя согласованность маппинга ключей сессий на диске /newвнутри темы переписывает строку привязки на новый ID сессии, чтобы следующее сообщение попало в свежую сессию- Темы из
extra.dm_topicsникогда не переименовываются автоматически — имя, выбранное оператором, сохраняется даже при включённом мультисессионном режиме extra.disable_topic_auto_rename: trueотключает автопереименование для всех тем чата (включая созданные через Threaded Mode)- Тема General (закреплённая вверху) в DM с включёнными форумными темами считается корневым лобби — независимо от того, приходят ли её сообщения с
message_thread_id=1или без thread_id - Напоминания корневого лобби ограничены одним сообщением в 30 секунд на пару (профиль, чат) — пользователь, забывший про включённый режим тем и написавший десять промптов в корень, не получит десять ответов, а два мультиплексных профиля с общим идентификатором чата не заглушают напоминания друг друга
- Скриншоты настроек BotFather отправляются не чаще одного раза в 5 минут на пару (профиль, чат) — повторные попытки
/topic, пока настройки тем всё ещё выключены, не приведут к повторной загрузке той же картинки /bg <prompt>внутри темы доставляет результат обратно в ту же тему; фоновые сессии не вызывают автопереименование/topicзакрыт проверкой авторизации бота — неавторизованные DM получают отказ
Отключение мультисессионного режима
Отправьте /topic off в корневом DM. Hermes сбрасывает флаг в пространстве имён этого профиля, очищает привязки (thread_id → session_id) этого профиля для чата, и корневой DM превращается обратно в обычный Hermes-чат. Созданные темы в Telegram не удаляются — они просто перестают работать как независимые сессии. /topic снова включит режим.
Для ручной очистки (например, массовый сброс по многим чатам) ограничивайте строки по profile_name (для установок с одним профилем это default):
sqlite3 ~/.hermes/state.db \
"UPDATE telegram_dm_topic_mode SET enabled = 0
WHERE profile_name = 'default' AND chat_id = '<ваш_chat_id>';
DELETE FROM telegram_dm_topic_bindings
WHERE profile_name = 'default' AND chat_id = '<ваш_chat_id>';"
Откат Hermes на старую версию
Если откатиться на версию Hermes до /topic — фича просто перестаёт работать. Таблицы telegram_dm_topic_mode и telegram_dm_topic_bindings остаются в state.db, но старый код их игнорирует. DM возвращаются к нативной изоляции по тредам (каждый message_thread_id получает свою сессию через build_session_key), так что существующие темы Telegram продолжают работать как параллельные сессии. Корневой DM перестаёт быть лобби. Обновление обратно восстанавливает мультисессионный режим именно в том состоянии, в котором он был.
Привязка навыков к темам групп
Супергруппы с включённым режимом тем (forum topics) уже получают изоляцию по темам — каждый thread_id маппится на свою сессию. Но иногда нужно автозагружать навык при получении сообщений в конкретной теме группы, как и в DM-темах.
Сценарий
Командная супергруппа с темами форума по направлениям:
- Тема Engineering → автозагрузка навыка
software-development - Тема Research → автозагрузка навыка
arxiv - Тема General → без навыка, универсальный ассистент
Конфигурация
Добавьте привязки под platforms.telegram.extra.group_topics в ~/.hermes/config.yaml:
platforms:
telegram:
extra:
group_topics:
- chat_id: -1001234567890 # ID супергруппы
topics:
- name: Engineering
thread_id: 5
skill: software-development
- name: Research
thread_id: 12
skill: arxiv
- name: General
thread_id: 1
# без навыка — универсальный режим
Поля:
| Поле | Обязательно | Описание |
|---|---|---|
chat_id | Да | Числовой ID супергруппы (отрицательное число, начинается с -100) |
name | Нет | Читаемое название темы (только для справки) |
thread_id | Да | ID темы форума Telegram — виден в ссылках t.me/c/<group_id>/<thread_id> |
skill | Нет | Навык для автозагрузки в новых сессиях этой темы |
Как это работает
- При получении сообщения в теме группы Hermes ищет
chat_idиthread_idв конфигеgroup_topics - Если у найденной записи есть поле
skill— навык автозагружается, как в DM-темах - Темы без
skillполучают только изоляцию сессий (поведение без изменений) - Незнакомые
thread_idилиchat_idпропускаются без ошибок
Отличия от DM Topics
| DM Topics | Group Topics | |
|---|---|---|
| Ключ конфига | extra.dm_topics | extra.group_topics |
| Создание тем | Hermes создаёт темы через API, если thread_id не задан | Администратор создаёт темы в Telegram |
thread_id | Заполняется автоматически после создания | Нужно задать вручную |
icon_color / icon_custom_emoji_id | Поддерживается | Не применимо (внешний вид контролирует администратор) |
| Привязка навыка | ✓ | ✓ |
| Изоляция сессий | ✓ | ✓ (уже встроена для форумных тем) |
Чтобы найти thread_id темы, откройте её в Telegram Web или Desktop и посмотрите на URL: https://t.me/c/1234567890/5 — последнее число (5) и есть thread_id. chat_id для супергрупп — это ID группы с префиксом -100 (например, группа 1234567890 → -1001234567890).
Последние обновления Bot API
- Bot API 9.4 (февраль 2026): Personal Chat Topics — боты могут создавать темы форума в личных диалогах через
createForumTopic. Hermes использует это для двух функций: оператор-настраиваемых личных тем (через конфиг, фиксированный список) и мультисессионного DM-режима (активируется пользователем через/topic, неограниченное число тем). - Политика конфиденциальности: Telegram теперь требует от ботов наличия политики конфиденциальности. Задайте её через BotFather командой
/setprivacy_policy, или Telegram сгенерирует заглушку. Особенно важно для публичных ботов. - Bot API 9.5 (март 2026): нативный стриминг через
sendMessageDraft. Hermes поддерживает нативный API черновиков Telegram как опциональный транспорт для личных чатов. По умолчанию остаётся устаревший путь черезeditMessageText— из-за видимого сворачивания и перерисовки черновиков в некоторых клиентах.
Транспорт стриминга (gateway.streaming.transport)
При включённом стриминге (gateway.streaming.enabled: true) Hermes выбирает один из четырёх транспортов:
| Значение | Поведение |
|---|---|
auto (по умолчанию) | Нативный черновиковый стриминг в поддерживаемых чатах (сейчас — Telegram DM); в остальных — старый путь через edit. При сбое кадра черновика — плавный откат. |
draft | Принудительные нативные черновики. Логирует даунгрейд и откатывается на edit в несовместимых чатах (группы, темы). |
edit | Прогрессивный editMessageText для всех типов чатов. |
off | Стриминг отключён (только финальный ответ, без промежуточных обновлений). |
В ~/.hermes/config.yaml:
gateway:
streaming:
enabled: true
transport: auto # auto | draft | edit | off
Режим edit в DM — шлюз отправляет предварительное сообщение и прогрессивно обновляет его через editMessageText, избегая эффекта сворачивания/перерисовки черновика.
Режим auto или draft в DM — Telegram показывает анимированный черновик, обновляемый токен за токеном. По завершении ответ доставляется как обычное сообщение, и предпросмотр черновика естественно исчезает на клиенте. Черновики не имеют ID сообщения, поэтому в истории чата остаётся только финальный ответ.
Группы, супергруппы, форумные темы — Telegram ограничивает sendMessageDraft личными чатами. Для всего остального шлюз прозрачно откатывается на edit — пользовательский опыт прежний.
При сбое кадра черновика — любой сбой (сетевая ошибка, отказ сервера, старая версия python-telegram-bot) переключает текущий ответ обратно на edit. Следующий ответ снова попробует черновик.
Рендеринг: Rich Messages, таблицы и превью ссылок
Rich Messages (Bot API 10.1). Финальные ответы с конструкциями, которые устаревший путь MarkdownV2 портит — таблицы, списки задач, сворачиваемые <details>, блочная математика, — отправляются через нативный sendRichMessage на сыром markdown агента, поэтому рендерятся нативно без сплющивания на стороне клиента. В DM по умолчанию rich_drafts: false оставляет потоковый предпросмотр простым — он идёт по эфемерному транспорту черновиков Telegram со старым рендерингом (таблицы и прочие конструкции, доступные только rich-режиму, остаются в предпросмотре сырым markdown), — а готовый ответ затем закрепляется через sendRichMessage. При rich_drafts: true живой предпросмотр тоже переходит на sendRichMessageDraft. Стриминг на основе редактирования может финализировать существующий предпросмотр на месте через параметр rich_message у editMessageText. Обычные ответы (простая проза, жирный/курсив, простые списки) остаются на пути MarkdownV2 ради согласованной насыщенности шрифта и отступов в разных клиентах.
Rich-путь автоматически пропускается, когда содержимое превышает лимит rich-текста в 32 768 символов, а любой отказ Telegram (неподдерживаемый endpoint на старой python-telegram-bot, ошибка парсера, слишком крупные блоки/столбцы) прозрачно откатывается на путь MarkdownV2 — сообщение не теряется. Временные и сетевые ошибки при этом не пересылаются молча (дубля финального сообщения не будет).
Откат на MarkdownV2. Когда rich-путь для сообщения недоступен, Hermes конвертирует markdown в MarkdownV2. Поскольку в MarkdownV2 нет нативного синтаксиса таблиц, pipe-таблицы нормализуются:
- Маленькие таблицы превращаются в сгруппированные по строкам списки — каждая строка становится читаемым маркированным списком под заголовками столбцов. Хорошо для 2–4 столбцов и коротких ячеек.
- Большие и широкие таблицы откатываются в блок кода с выровненными столбцами, чтобы ничего не схлопывалось.
Rich-сообщения включаются опционально. По умолчанию используется устаревший путь MarkdownV2, потому что в текущих клиентах Telegram rich-сообщения Bot API трудно скопировать как обычный текст — особенно неудобно с командными сниппетами и при переносе на мобильный. Чтобы включить нативный рендеринг таблиц/списков задач/details/математики:
gateway:
platforms:
telegram:
extra:
rich_messages: true
rich_drafts: false
allow_cjk_rich_messages: false
Эта настройка нужна для совместимости с рендерингом/копированием в конкретных клиентах; Hermes и так автоматически откатывается, когда Telegram отклоняет rich-вызов. rich_drafts управляет тем, рендерится ли потоковый предпросмотр в DM как rich (sendRichMessageDraft), и по умолчанию выключен, потому что Telegram Desktop/macOS может визуально накладывать кадры rich-черновика друг на друга, пока чат не перерисуется; при выключенном флаге предпросмотр стримится простым, а финал всё равно приходит нативным Rich Message.
Текст CJK (китайский, японский, корейский и редкие расширения иероглифов) по умолчанию остаётся на устаревшем пути MarkdownV2, потому что затронутые клиенты Telegram Desktop/macOS рендерили rich-сообщения Bot API с наложением глифов CJK. Если у вас клиент без этой проблемы и вы предпочитаете нативные rich-таблицы, списки задач, details и математику для CJK-контента, поставьте allow_cjk_rich_messages: true рядом с rich_messages: true — осознанно приняв этот риск на стороне клиента.
Если хочется только вернуть устаревшее поведение «всегда code-block» для таблиц, оставив rich-сообщения включёнными, отключите нормализацию таблиц через telegram.pretty_tables: false в config.yaml (по умолчанию true).
Превью ссылок. Telegram автоматически генерирует превью для URL в сообщениях бота. Если нужно их отключить (длинный вывод /tools, ответ агента с десятью ссылками и т. п.):
gateway:
platforms:
telegram:
extra:
disable_link_previews: true
При включении Hermes прикрепляет к каждому исходящему сообщению LinkPreviewOptions(is_disabled=True) и откатывается к устаревшему параметру disable_web_page_preview на старых версиях python-telegram-bot.
Длинные ответы и контроль флуда. Ответ длиннее лимита Telegram в 4096 символов отправляется пронумерованными частями ((1/3), (2/3), …). В один чат ответы уходят по одному, так что отчёт по расписанию и ответ в личке, пришедшие одновременно, не перемешают свои части, а загрузка файла не вклинится между двумя частями текста, к которому относится. Если контроль флуда Telegram отклонит часть посередине, Hermes после окончания штрафа продолжит с отклонённой части, а не будет заново слать уже показанные; пока чат находится в известном окне штрафа, дальнейшие отправки в него локально отклоняются (без лишних запросов, которые удлинили бы штраф). Штраф дольше, чем шлюз готов ждать на месте, передаётся журналу доставки, который повторно доставит ответ с пометкой, что часть его, возможно, уже пришла выше.
Списки доступа для групп
В группах и форумах Telegram есть два независимых механизма контроля доступа:
- ID пользователей-отправителей (
group_allow_from/TELEGRAM_GROUP_ALLOWED_USERS) — список отправителей, действующий только для сообщений из групп/форумов. Используйте, когда хотите дать конкретным пользователям доступ к боту в группах, не предоставляя им доступ в ЛС (что дало быTELEGRAM_ALLOWED_USERS). - ID чатов (
group_allowed_chats/TELEGRAM_GROUP_ALLOWED_CHATS) — список чатов. Любой участник этих групп/форумов может взаимодействовать с ботом. Удобно для командных и саппорт-ботов, где членство в группе само по себе является признаком доступа.
gateway:
platforms:
telegram:
extra:
# Глобальный доступ (ЛС + группы). Эти пользователи всегда могут вызвать бота.
allow_from:
- "123456789"
# ID отправителей, разрешённых только в группах/форумах. Доступа в ЛС не даёт.
group_allow_from:
- "987654321"
# Целые группы/форумы — любой участник авторизован.
group_allowed_chats:
- "-1001234567890"
Эквивалентные переменные окружения:
TELEGRAM_ALLOWED_USERS="123456789"
TELEGRAM_GROUP_ALLOWED_USERS="987654321"
TELEGRAM_GROUP_ALLOWED_CHATS="-1001234567890"
Поведение:
TELEGRAM_ALLOWED_USERSохватывает все типы чатов (ЛС, группы, форумы).TELEGRAM_GROUP_ALLOWED_USERSавторизует указанных отправителей только в группах/форумах. В ЛС к боту они всё равно не попадут без записи вTELEGRAM_ALLOWED_USERS.- Чат в
TELEGRAM_GROUP_ALLOWED_CHATSавторизует всех участников этого чата, независимо от отправителя. *в любом из этих списков разрешает любого отправителя/чат.- Всё это работает поверх фильтров упоминаний/паттернов и поверх
group_topics+ignored_threads.
Миграция с версий до PR #17686
До этого изменения TELEGRAM_GROUP_ALLOWED_USERS был единственным инструментом, и в него писали ID чатов. Для обратной совместимости значения, похожие на ID чатов (начинаются с -), в TELEGRAM_GROUP_ALLOWED_USERS по-прежнему обрабатываются как ID чатов с однократным предупреждением в лог. Миграция:
# Старый вариант (работает, но устарел)
TELEGRAM_GROUP_ALLOWED_USERS="-1001234567890"
# Новый вариант
TELEGRAM_GROUP_ALLOWED_CHATS="-1001234567890"
Гостевой режим по @mention (guest_mode)
В стандартной настройке group_allowed_chats — жёсткий фильтр: сообщения из групп вне списка молча отбрасываются, даже если участник явно упомянул бота. Это правильный дефолт для саппорт- и командных ботов.
Для более непринуждённых сценариев — чаты с друзьями, где бот должен быть по большей части молчалив, но доступен по прямому пингу — включите guest_mode:
gateway:
platforms:
telegram:
extra:
group_allowed_chats:
- "-1001234567890" # ваша основная группа из списка
guest_mode: true # в неразрешённых группах: отвечать только на @mention
Переменная окружения:
TELEGRAM_GUEST_MODE=true
По умолчанию: false.
При guest_mode: true сообщение из неразрешённой группы обрабатывается только при явном @mention. Упоминание нужно в каждом обращении — у гостевых взаимодействий нет прилипания сессии, так что бот не начнёт сам подхватывать тред в чате с друзьями.
ЛС и разрешённые группы ведут себя точно как прежде.
Управление доступом к командам
По умолчанию каждый авторизованный пользователь может запускать любую команду-слэш. Чтобы разделить список на администраторов (полный доступ к командам) и обычных пользователей (только явно разрешённые команды), добавьте allow_admin_from и user_allowed_commands в блок extra платформы:
gateway:
platforms:
telegram:
extra:
# Существующие списки доступа (без изменений)
allow_from:
- "123456789" # администратор
- "555555555" # обычный пользователь
- "777777777" # обычный пользователь
# Администраторы получают все команды-слэш (встроенные + плагины)
allow_admin_from:
- "123456789"
# Неадмины из allow_from могут запускать только эти команды.
# /help и /whoami всегда разрешены.
user_allowed_commands:
- status
- model
- history
# Опционально: отдельные списки для групп
group_allow_admin_from:
- "123456789"
group_user_allowed_commands:
- status
Поведение:
- Пользователь из
allow_admin_fromв данном контексте (ЛС или группа) может запускать любую зарегистрированную команду — встроенную и из плагинов — через живой реестр. - Пользователь из
allow_from, но не изallow_admin_from, может запускать только команды изuser_allowed_commands, плюс всегда разрешённый минимум:/helpи/whoami. - Обычный чат (не команды-слэш) не затрагивается. Неадминистраторы по-прежнему общаются с агентом — просто без произвольных команд.
- Обратная совместимость: если
allow_admin_fromдля контекста не задан, ограничение команд не работает. Существующие установки продолжают работать без изменений. - Статус администратора в ЛС не даёт прав администратора в группах. У каждого контекста свой список.
- Если задан только
group_allow_admin_from, режим ЛС остаётся неограниченным (для обратной совместимости).
/whoami покажет активный контекст, ваш уровень (admin / user / unrestricted) и доступные команды-слэш.
Интерактивный выбор модели
Команда /model без аргументов открывает интерактивную inline-клавиатуру для смены модели:
- Выбор провайдера — кнопки с названием каждого доступного провайдера и числом моделей (например, «OpenAI (15)», «✓ Anthropic (12)» — текущий помечается).
- Выбор модели — постраничный список с навигацией Prev/Next, кнопкой Back и Cancel.
Текущая модель и провайдер отображаются вверху. Вся навигация происходит редактированием одного сообщения — без мусора в чате.
Если знаете точное имя модели, введите /model <name> напрямую. /model <name> --global сохранит смену между сессиями.
Запасные IP через DNS-over-HTTPS
В некоторых ограниченных сетях api.telegram.org может резолвиться в недоступный IP. Адаптер Telegram включает механизм запасных IP, который прозрачно повторяет соединение через альтернативные адреса, сохраняя правильное имя хоста TLS и SNI.
Как это работает
- Если задан
TELEGRAM_FALLBACK_IPS— используются эти IP напрямую. - Иначе адаптер автоматически запрашивает Google DNS и Cloudflare DNS через DNS-over-HTTPS (DoH) для поиска альтернативных IP
api.telegram.org. - Известные IPv4-адреса Telegram API пробуются раньше, чем dual-stack-хост
api.telegram.org. Заблокированный в чёрную дыру IPv6-путь может зависать внутриconnect()без ошибки — раньше это блокировало event loop, из-за чего 30-секундный дедлайн инициализации так и не срабатывал. - Если DoH тоже заблокирован или отвечает с таймаутом, как крайний вариант используется хардкод-список IPv4 (
149.154.166.110,149.154.167.220) — тот же приоритет IPv4-first. Имя хоста остаётся последним резервом. - После успешного соединения путь становится «прилипшим» — последующие запросы используют его напрямую. Имя хоста сохраняется как последний резерв для сетей только с IPv6.
Конфигурация
# Явные запасные IP (через запятую)
TELEGRAM_FALLBACK_IPS=149.154.167.220,149.154.167.221
Или в ~/.hermes/config.yaml:
platforms:
telegram:
extra:
fallback_ips:
- "149.154.167.220"
Обычно настраивать вручную не нужно. Автообнаружение через DoH справляется с большинством ограниченных сетей. TELEGRAM_FALLBACK_IPS нужен, только если DoH тоже заблокирован. Если на хосте сломан IPv6, можно также задать network.force_ipv4: true в config.yaml, чтобы пропускать AAAA-запросы для всего процесса.
Поддержка прокси через переменные окружения
Если сеть требует HTTP-прокси для выхода в интернет (распространено в корпоративных средах), адаптер Telegram автоматически читает стандартные переменные окружения прокси.
Поддерживаемые переменные
Адаптер проверяет их по порядку, используя первую установленную:
HTTPS_PROXYHTTP_PROXYALL_PROXYhttps_proxy/http_proxy/all_proxy(строчные варианты)
Конфигурация
Задайте прокси в окружении перед запуском шлюза:
export HTTPS_PROXY=http://proxy.example.com:8080
hermes gateway
Или в ~/.hermes/.env:
HTTPS_PROXY=http://proxy.example.com:8080
Прокси применяется к основному транспорту и всем запасным IP-транспортам. Дополнительная настройка Hermes не нужна — достаточно задать переменную окружения.
Это покрывает кастомный резервный транспортный слой для соединений Telegram. Стандартный клиент httpx, используемый в остальном коде, уже поддерживает прокси через переменные окружения нативно.
Реакции на сообщения
Бот может ставить эмодзи-реакции как визуальный индикатор обработки:
- 👀 когда бот начинает обрабатывать ваше сообщение
- 👍 при успешной доставке ответа
- 👎 при ошибке
Реакции отключены по умолчанию. Включить в config.yaml:
telegram:
reactions: true
Или через переменную окружения:
TELEGRAM_REACTIONS=true
В отличие от Discord (где реакции аддитивны), Bot API Telegram заменяет все реакции бота одним вызовом. Переход с 👀 на 👍/👎 происходит атомарно — оба значка одновременно не появятся.
Если у бота нет прав на реакции в группе, вызовы молча проваливаются, а обработка сообщений продолжается в штатном режиме.
Промпты для конкретных каналов
Назначайте временные системные промпты конкретным Telegram-группам или темам форума. Промпт инжектируется на каждом ходу в рантайме — никогда не сохраняется в истории — и изменения вступают в силу немедленно.
telegram:
channel_prompts:
"-1001234567890": |
Ты научный ассистент. Фокусируйся на академических источниках,
цитатах и лаконичных синтезах.
"42": |
Эта тема посвящена обратной связи по текстам. Отвечай тепло
и конструктивно.
Ключи — ID чатов (групп/супергрупп) или ID тем форума. Для форумных групп промпт темы перекрывает промпт группы:
- Сообщение в теме
42внутри группы-1001234567890→ применяется промпт темы42 - Сообщение в теме
99(без явной записи) → откатывается на промпт группы-1001234567890 - Сообщение в группе без записи → промпт не применяется
Числовые YAML-ключи автоматически нормализуются в строки.
Решение проблем
| Проблема | Решение |
|---|---|
| Бот вообще не отвечает | Проверьте правильность TELEGRAM_BOT_TOKEN. Смотрите логи hermes gateway на ошибки. |
| Бот отвечает «unauthorized» | Ваш User ID отсутствует в TELEGRAM_ALLOWED_USERS. Проверьте через @userinfobot. |
| Бот игнорирует сообщения в группе | Скорее всего, включён режим конфиденциальности. Отключите его (шаг 3) или назначьте бота администратором. После смены настройки конфиденциальности удалите и добавьте бота заново. |
| Голосовые сообщения не расшифровываются | Проверьте доступность STT: установите faster-whisper для локальной расшифровки или задайте GROQ_API_KEY / VOICE_TOOLS_OPENAI_KEY в ~/.hermes/.env. |
| Голосовые ответы приходят как файлы, а не пузырьки | Установите ffmpeg (нужен для конвертации Edge TTS в Opus). |
| Токен бота отозван/невалиден | Сгенерируйте новый через /revoke, затем /newbot или /token в BotFather. Обновите .env. |
| Вебхук не получает обновления | Проверьте публичную доступность TELEGRAM_WEBHOOK_URL (тестируйте через curl). Убедитесь, что платформа/реверс-прокси маршрутизирует входящий HTTPS на локальный порт из TELEGRAM_WEBHOOK_PORT (номера не обязаны совпадать). SSL/TLS должен быть активен — Telegram отправляет только на HTTPS. Проверьте правила файрвола. |
Подтверждение выполнения команд
Когда агент пытается выполнить потенциально опасную команду, он запрашивает подтверждение в чате:
⚠️ Эта команда потенциально опасна (рекурсивное удаление). Ответьте «да» для подтверждения.
Ответьте “yes”/“y” для одобрения или “no”/“n” для отказа.
Интерактивные вопросы (clarify)
Когда агент вызывает инструмент clarify — чтобы уточнить предпочтения, получить обратную связь после задачи или проверить перед нетривиальным решением — Telegram рендерит вопрос с inline-кнопками:
❓ Какой фреймворк использовать для дашборда?
[1. Next.js] [2. Remix] [3. Astro] [✏️ Другое (введите ответ)]
Нажмите кнопку или нажмите Другое и введите свободный текст (следующее отправленное сообщение станет ответом). Открытые вопросы без готовых вариантов пропускают кнопки и просто ждут следующего сообщения.
Тайм-аут ответа настраивается через agent.clarify_timeout в ~/.hermes/config.yaml (по умолчанию 3600 секунд). Если не ответить в срок, агент разблокируется с ответом "outcome": "timed_out" и действует самостоятельно. Чтобы пропустить вопрос, ответьте skip.
Если Telegram не может отрисовать карточку с кнопками (Bot API её отклоняет или отправка не удалась после 15-секундного окна подтверждения), Hermes задаёт тот же вопрос заново обычным сообщением с нумерованным списком, а ваш набранный ответ (номер или текст варианта) принимается как ответ. Когда не удаётся доставить даже это, агент сразу отпускается с [clarify prompt could not be delivered], вместо того чтобы высиживать таймаут и принимать тишину за ваше молчание.
Управление push-уведомлениями
Telegram присылает push-уведомление на каждое сообщение от бота. При длинных агентских ходах с промежуточными пузырьками о работе инструментов, стриминг-обновлениями и статусными колбэками это быстро становится назойливым.
| Режим | Поведение |
|---|---|
important (по умолчанию) | Уведомления только на финальные ответы, запросы подтверждения и подтверждения команд. Прогресс инструментов, куски стриминга и статусные сообщения доставляются с disable_notification=true. |
all | Уведомление на каждое исходящее сообщение. Унаследованное поведение; включайте, если действительно хотите знать о каждом вызове инструмента. |
Настройка в ~/.hermes/config.yaml:
display:
platforms:
telegram:
notifications: important # или "all"
Быстрое переключение через переменную окружения:
HERMES_TELEGRAM_NOTIFICATIONS=all
Неизвестные значения логируют предупреждение и откатываются на important.
Статусные сообщения редактируются на месте
Адаптер Telegram маршрутизирует повторяющиеся статусные колбэки агента («Сжимаю контекст…», «Вызываю инструмент…») через send_or_update_status(): кэш {(chat_id, status_key) → message_id} позволяет редактировать существующий пузырёк при повторных отправках вместо добавления нового. Разные status_key получают свои сообщения; разные чаты не пересекаются. Если редактирование не удаётся (пользователь удалил сообщение или оно слишком старое), запись из кэша удаляется и следующий emit создаёт новое сообщение с новым кэшированием. Настройка не нужна — это поведение Telegram по умолчанию. Другие адаптеры без send_or_update_status используют обычный send().
Закрепление входящего сообщения во время хода агента
Когда пользователь отправляет сообщение, запускающее ход агента, адаптер Telegram закрепляет его на время хода и открепляет по завершении ответа — лёгкий визуальный индикатор того, что бот активно работает с сообщением, а не игнорирует его. Закрепление использует disable_notification=true. Настройка не нужна.
Безопасность
Всегда задавайте TELEGRAM_ALLOWED_USERS — без этого шлюз по умолчанию отказывает всем пользователям.
Никогда не раскрывайте токен бота публично. При компрометации немедленно отзовите его через /revoke в BotFather.
Подробнее — в документации по безопасности. Для динамического управления доступом пользователей смотрите раздел DM-сопряжение.