Диагностика и FAQ¶
Матрица «симптом → причина → решение» по реальным случаям, затем частые вопросы.
Симптом → причина → решение¶
| Симптом | Причина | Решение |
|---|---|---|
Соединение закрывается с кодом 1008, приходит error{code:"auth_failed"} |
токен в приложении ≠ ни одному из MOBILE_TOKEN / MOBILE_EXTRA_TOKENS, или device.id отсутствует в MOBILE_ALLOWED_DEVICES |
сверить токен с владельцем агента; если ограничены устройства — добавить device.id или убрать фильтр; повторять бессмысленно |
Приходит error{code:"forbidden"} (+ 1008 при подключении) |
токен привязан к другому device.id (device_id=token), занят чужой id другим токеном, либо ответ на карточку чужого устройства |
подключаться под своим device.id (тем, что привязан к токену); карточку закрывает только устройство, которому она показана |
error{code:"forbidden"} на кадре deliver |
deliver шлёт не cron: соединение не с loopback и токена нет в MOBILE_DELIVER_TOKENS |
служебную доставку выполняет cron/hermes send с той же машины (loopback); при доставке извне — добавить токен в MOBILE_DELIVER_TOKENS |
error{code:"too_big"} / bad_frame при медиа-загрузке |
превышено число незавершённых загрузок (8 на устройство), суммарный буфер устройства (> 8 МиБ) или parts > 2048 |
дождаться завершения текущих загрузок; не держать много открытых серий; резать файл крупнее 4 КиБ на кусок; при отключении буферы освобождаются |
ready пришёл, но ответов агента нет |
устройство ещё не одобрено Hermes (pairing) | на машине агента: hermes pairing list → hermes pairing approve mobile <request-id>; либо заранее MOBILE_ALLOWED_USERS=<id пользователя> |
| Ответ агента: «No home channel is set» / про pairing-код | штатное поведение Hermes при первом контакте незнакомого пользователя | одобрить pairing; либо отправить /sethome, чтобы этот чат стал домашним (для cron-доставки) |
error{code:"device_offline"} при доставке cron |
приложение не подключено в момент доставки | мобильная доставка требует живого соединения: держите приложение подключённым в нужный момент или доставляйте на устройство, которое обычно онлайн (MOBILE_HOME_DEVICE) |
| Медиа не приходит | обрыв серии кусков (part/parts), либо превышен лимит 8 МиБ / кадр 16 МиБ |
досылать все part до parts-1 с одним id; крупный файл слать кусками по ~3 МиБ или сжать; при too_big — то же |
| Дубли сообщений при повторной отправке | не выставляется постоянный id, либо используется новый id при повторе |
держите id постоянным для сообщения и повторяйте его при переотправке — сервер игнорирует повтор |
| Соединение не устанавливается: 404 / 426 на публичном адресе | reverse-proxy не проксирует WebSocket (нет Upgrade), либо неверный путь |
проксировать маршрут (handle /ws* в Caddy) с апгрейдом до WS; сверить путь с MOBILE_PATH (по умолчанию /ws) |
Адаптер не поднимается: bind_failed: не удалось занять 127.0.0.1:8787 |
порт 8787 занят другим процессом | ss -ltnp \| grep 8787; освободить порт или сменить MOBILE_PORT и обновить прокси |
config_missing: MOBILE_TOKEN не задан |
нет токена в .env профиля |
платформа без токена не поднимается (защита): добавить MOBILE_TOKEN в ~/.hermes/.env и перезапустить шлюз |
deps_missing / «нет websockets» |
пакет websockets недоступен в окружении |
адаптер зависимостей не ставит: пакет входит в Hermes — обновите Hermes |
Плагин не виден в hermes plugins list |
неверный путь или не включён в конфиге | проверить ~/.hermes/plugins/<name>/plugin.yaml и plugins.enabled в config.yaml |
Первый кадр не hello → error{code:"bad_frame"} + 1008 |
клиент отправил text/media до рукопожатия |
первым кадром всегда отправлять hello |
| Карточка не закрывается / ответ «проглочен» | карточка истекла (prompt_done{expired:true}) или неверный prompt_id |
отвечать значением из options сразу; при истечении карточка просто закрывается |
Формат аудио не принят: unsupported_frame |
format не wav/ogg |
отправлять WAV 16 кГц моно или OGG |
Непонятный тип медиа: unsupported_frame |
kind вне image/video/document/audio |
использовать допустимые значения |
Проверка руками
wscat -c "ws://127.0.0.1:8787/ws", затем первым кадром отправить
{"t":"hello","token":"<токен>","device":{"id":"cli"}} — должен прийти ready (токен в URL
?token= не принимается). Дальше {"t":"text","id":"t1","text":"привет"}.
FAQ¶
Обязателен ли SDK? Нет. Протокол — это JSON-кадры поверх WebSocket; подойдёт любой рантайм. SDK (TypeScript/Python) берёт на себя переподключение, нарезку/склейку и разбор кадров.
Что такое session в кадре ready?
Идентификатор сессии в Hermes: mobile:<device.id>. Он же — адрес доставки для
hermes send --to mobile:<device.id> и cron.
Куда пропадает история, если переустановить приложение? Никуда: история и память живут на стороне Hermes в профиле агента. Приложение — только клиент.
Можно ли использовать один device.id на нескольких телефонах?
Технически да, но это будет одна сессия на всех. Для раздельных диалогов давайте каждому
устройству свой device.id. Токеном, привязанным к устройству (MOBILE_EXTRA_TOKENS=device_id=token),
чужой id занять нельзя — придёт forbidden.
Что такое MOBILE_DELIVER_TOKENS?
Кадр deliver (служебная доставка от cron) принимается только с loopback-адреса или от соединения
с токеном из этого списка; остальным — forbidden. В типовой схеме (cron на той же машине) задавать
переменную не нужно — loopback-соединение и так разрешено.
Чем MOBILE_ALLOWED_USERS отличается от MOBILE_ALLOWED_DEVICES?
Первый — про пользователей (штатная авторизация и pairing Hermes), второй — про устройства
(дополнительный фильтр адаптера). Это разные переменные и разные сущности — см.
Как всё устроено.
Почему ответ приходит не сразу, а «дорисовывается»?
Если на стороне агента включён стриминг: сначала приходит сообщение целиком, затем правки
message с edit: true и тем же id. Перерисовывайте по id, иначе увидите дубли.
Работает ли доставка, когда приложение закрыто?
Нет. Мобильная доставка (cron, hermes send) требует живого подключения: иначе вернётся
device_offline. История при этом не теряется — агент обслуживает сессию и без мобильного клиента.
Как отозвать доступ у одного устройства?
Убрать его токен из MOBILE_TOKEN/MOBILE_EXTRA_TOKENS (или удалить device.id из
MOBILE_ALLOWED_DEVICES) и перезапустить шлюз: hermes gateway restart. Подробнее —
Безопасность.