WeCom (Корпоративный WeChat)
Подключите Hermes к WeCom (企业微信), корпоративной мессенджер-платформе от Tencent. Адаптер использует WebSocket-шлюз AI Bot от WeCom для двусторонней связи в реальном времени — не требует публичного эндпоинта или webhook.
Предварительные требования
-
Учётная запись организации WeCom
-
AI Bot, созданный в консоли администратора WeCom
-
Bot ID и Secret со страницы учётных данных бота
-
Python-пакеты:
aiohttpиhttpx
Настройка
Шаг 1: Создание AI Bot
Рекомендуется: Сканирование для создания (одна команда)
hermes gateway setup
Выберите WeCom и отсканируйте QR-код с помощью мобильного приложения WeCom. Hermes автоматически создаст приложение-бота с правильными разрешениями и сохранит учётные данные.
Мастер настройки выполнит:
-
Отображение QR-кода в вашем терминале
-
Ожидание сканирования с помощью мобильного приложения WeCom
-
Автоматическое получение Bot ID и Secret
-
Проведение по настройке контроля доступа
Альтернатива: Ручная настройка
Если сканирование недоступно, мастер переключается на ручной ввод:
-
Войдите в Консоль администратора WeCom
-
Перейдите в Приложения → Создать приложение → AI Bot
-
Настройте имя и описание бота
-
Скопируйте Bot ID и Secret со страницы учётных данных
-
Запустите
hermes gateway setup, выберите WeCom и введите учётные данные по запросу
Шаг 2: Настройка Hermes
Вариант A: Интерактивная настройка (рекомендуется)
hermes gateway setup
Выберите WeCom и следуйте подсказкам. Мастер проведёт вас через:
-
Учётные данные бота (через сканирование QR или ручной ввод)
-
Настройки контроля доступа (белый список, режим сопряжения или открытый доступ)
-
Домашний канал для уведомлений
Вариант B: Ручная настройка
Добавьте следующее в ~/.hermes/.env:
WECOM_BOT_ID=your-bot-id
WECOM_SECRET=your-secret
# Optional: restrict access
WECOM_ALLOWED_USERS=user_id_1,user_id_2
# Optional: home channel for cron/notifications
WECOM_HOME_CHANNEL=chat_id
Шаг 3: Запуск gateway
hermes gateway
Возможности
-
WebSocket-транспорт — постоянное соединение, не требует публичного эндпоинта
-
Личные и групповые сообщения — настраиваемые политики доступа
-
Белые списки отправителей по группам — точный контроль того, кто может взаимодействовать в каждой группе
-
Поддержка медиа — загрузка и скачивание изображений, файлов, голоса, видео
-
AES-зашифрованные медиа — автоматическая расшифровка входящих вложений
-
Контекст цитирования — сохраняет структуру переписки при ответах
-
Рендеринг Markdown — форматированные текстовые ответы
-
Потоковая передача в режиме ответа — связывает ответы с контекстом входящего сообщения
-
Автопереподключение — экспоненциальная задержка при разрывах соединения
Параметры конфигурации
Установите их в config.yaml в разделе platforms.wecom.extra:
| Ключ | По умолчанию | Описание |
|---|---|---|
bot_id |
— | WeCom AI Bot ID (обязательно) |
secret |
— | WeCom AI Bot Secret (обязательно) |
websocket_url |
wss://openws.work.weixin.qq.com |
URL WebSocket-шлюза |
dm_policy |
open |
Доступ к ЛС: open, allowlist, disabled, pairing |
group_policy |
open |
Доступ к группам: open, allowlist, disabled |
allow_from |
[] |
ID пользователей, разрешённых для ЛС (когда dm_policy=allowlist) |
group_allow_from |
[] |
ID групп, разрешённых для чата (когда group_policy=allowlist) |
groups |
{} |
Конфигурация по группам (см. ниже) |
Политики доступа
Политика ЛС
Определяет, кто может отправлять боту личные сообщения:
| Значение | Поведение |
|---|---|
open |
Любой может писать боту в ЛС (по умолчанию) |
allowlist |
Только пользователи из allow_from могут писать в ЛС |
disabled |
Все ЛС игнорируются |
pairing |
Режим сопряжения (для начальной настройки) |
WECOM_DM_POLICY=allowlist
Политика групп
Определяет, в каких группах бот отвечает:
| Значение | Поведение |
|---|---|
open |
Бот отвечает во всех группах (по умолчанию) |
allowlist |
Бот отвечает только в ID групп, указанных в group_allow_from |
disabled |
Все групповые сообщения игнорируются |
WECOM_GROUP_POLICY=allowlist
Белые списки отправителей по группам
Для точного контроля можно ограничить, какие пользователи могут взаимодействовать с ботом в определённых группах. Это настраивается в config.yaml:
platforms:
wecom:
enabled: true
extra:
bot_id: "your-bot-id"
secret: "your-secret"
group_policy: "allowlist"
group_allow_from:
- "group_id_1"
- "group_id_2"
groups:
group_id_1:
allow_from:
- "user_alice"
- "user_bob"
group_id_2:
allow_from:
- "user_charlie"
"*":
allow_from:
- "user_admin"
Как это работает:
-
Параметры
group_policyиgroup_allow_fromопределяют, разрешена ли группа в принципе. -
Если группа проходит верхнеуровневую проверку, список
groups.<group_id>.allow_from(если указан) дополнительно ограничивает, какие отправители внутри этой группы могут взаимодействовать с ботом. -
Запись группы
"*"служит значением по умолчанию для групп, не указанных явно. -
Записи в белом списке поддерживают символ
*для разрешения всех пользователей, и записи не чувствительны к регистру. -
Записи могут опционально использовать префиксы
wecom:user:илиwecom:group:— префикс автоматически удаляется.
Если для группы не настроен allow_from, все пользователи в этой группе разрешены (при условии, что сама группа проходит верхнеуровневую проверку политики).
Поддержка медиа
Входящие (получение)
Адаптер получает медиа-вложения от пользователей и кэширует их локально для обработки агентом:
| Тип | Как обрабатывается |
|---|---|
| Изображения | Скачиваются и кэшируются локально. Поддерживаются изображения по URL и в base64. |
| Файлы | Скачиваются и кэшируются. Имя файла сохраняется из исходного сообщения. |
| Голос | Текстовая расшифровка голосового сообщения извлекается, если доступна. |
| Смешанные сообщения | Смешанные сообщения WeCom (текст + изображения) разбираются, извлекаются все компоненты. |
Цитируемые сообщения: Медиа из цитируемых (на которые дан ответ) сообщений также извлекается, чтобы агент имел контекст того, на что отвечает пользователь.
Расшифровка AES-зашифрованных медиа
WeCom шифрует некоторые входящие медиа-вложения с помощью AES-256-CBC. Адаптер обрабатывает это автоматически:
-
Когда входящий медиа-элемент содержит поле
aeskey, адаптер скачивает зашифрованные байты и расшифровывает их с использованием AES-256-CBC с PKCS#7-выравниванием. -
AES-ключ — это декодированное из base64 значение поля
aeskey(должно быть ровно 32 байта). -
IV (вектор инициализации) формируется из первых 16 байт ключа.
-
Для этого требуется Python-пакет
cryptography(pip install cryptography).
Никакой дополнительной настройки не требуется — расшифровка происходит прозрачно при получении зашифрованного медиа.
Исходящие (отправка)
| Метод | Что отправляет | Лимит размера |
|---|---|---|
send |
Текстовые сообщения в Markdown | 4000 символов |
send_image / send_image_file |
Нативные сообщения-изображения | 10 МБ |
send_document |
Файловые вложения | 20 МБ |
send_voice |
Голосовые сообщения (только AMR для нативного голоса) | 2 МБ |
send_video |
Видеосообщения | 10 МБ |
Фрагментированная загрузка: Файлы загружаются фрагментами по 512 КБ через трёхэтапный протокол (init → chunks → finish). Адаптер обрабатывает это автоматически.
Автоматическое понижение: Когда медиа превышает лимит размера для нативного типа, но не превышает абсолютный лимит в 20 МБ, оно автоматически отправляется как обычное файловое вложение:
-
Изображения > 10 МБ → отправляются как файл
-
Видео > 10 МБ → отправляются как файл
-
Голос > 2 МБ → отправляется как файл
-
Аудио не в формате AMR → отправляется как файл (WeCom поддерживает только AMR для нативного голоса)
Файлы, превышающие абсолютный лимит в 20 МБ, отклоняются с отправкой информационного сообщения в чат.
Потоковые ответы в режиме ответа
Когда бот получает сообщение через callback WeCom, адаптер запоминает ID входящего запроса. Если ответ отправляется, пока контекст запроса ещё активен, адаптер использует режим ответа WeCom (aibot_respond_msg) с потоковой передачей, чтобы связать ответ непосредственно с входящим сообщением. Это обеспечивает более естественный опыт общения в клиенте WeCom.
Если контекст входящего запроса истёк или недоступен, адаптер переключается на упреждающую отправку сообщения через aibot_send_msg.
Режим ответа также работает для медиа: загруженные медиафайлы могут быть отправлены как ответ на исходное сообщение.
Подключение и переподключение
Адаптер поддерживает постоянное WebSocket-соединение со шлюзом WeCom по адресу wss://openws.work.weixin.qq.com.
Жизненный цикл соединения
-
Подключение: Открывает WebSocket-соединение и отправляет аутентификационный фрейм
aibot_subscribeс bot_id и secret. -
Heartbeat: Отправляет ping-фреймы прикладного уровня каждые 30 секунд для поддержания соединения.
-
Прослушивание: Непрерывно читает входящие фреймы и диспетчеризует callback'и сообщений.
Поведение при переподключении
При потере соединения адаптер использует экспоненциальную задержку для переподключения:
| Попытка | Задержка |
|---|---|
| 1-я | 2 секунды |
| 2-я | 5 секунд |
| 3-я | 10 секунд |
| 4-я | 30 секунд |
| 5+ | 60 секунд |
После каждого успешного переподключения счётчик задержки сбрасывается. Все ожидающие фьючерсы запросов завершаются ошибкой при отключении, чтобы вызывающие стороны не зависали бесконечно.
Дедупликация
Входящие сообщения дедуплицируются с использованием ID сообщений в окне 5 минут с максимальным кэшем на 1000 записей. Это предотвращает двойную обработку сообщений во время переподключения или сетевых сбоев.
Все переменные окружения
| Переменная | Обязательно | По умолчанию | Описание |
|---|---|---|---|
WECOM_BOT_ID |
✅ | — | WeCom AI Bot ID |
WECOM_SECRET |
✅ | — | WeCom AI Bot Secret |
WECOM_ALLOWED_USERS |
— | (пусто) | ID пользователей через запятую для белого списка на уровне gateway |
WECOM_HOME_CHANNEL |
— | — | ID чата для вывода cron/уведомлений |
WECOM_WEBSOCKET_URL |
— | wss://openws.work.weixin.qq.com |
URL WebSocket-шлюза |
WECOM_DM_POLICY |
— | open |
Политика доступа к ЛС |
WECOM_GROUP_POLICY |
— | open |
Политика доступа к группам |
Устранение неполадок
| Проблема | Решение |
|---|---|
WECOM_BOT_ID and WECOM_SECRET are required |
Установите обе переменные окружения или настройте в мастере установки |
WeCom startup failed: aiohttp not installed |
Установите aiohttp: pip install aiohttp |
WeCom startup failed: httpx not installed |
Установите httpx: pip install httpx |
invalid secret (errcode=40013) |
Проверьте, что secret соответствует учётным данным вашего бота |
Timed out waiting for subscribe acknowledgement |
Проверьте сетевое подключение к openws.work.weixin.qq.com |
| Бот не отвечает в группах | Проверьте настройку group_policy и убедитесь, что ID группы есть в group_allow_from |
| Бот игнорирует некоторых пользователей в группе | Проверьте списки allow_from для группы в разделе конфигурации groups |
| Ошибка расшифровки медиа | Установите cryptography: pip install cryptography |
cryptography is required for WeCom media decryption |
Входящее медиа зашифровано AES. Установите: pip install cryptography |
| Голосовые сообщения отправляются как файлы | WeCom поддерживает только формат AMR для нативного голоса. Другие форматы автоматически понижаются до файла. |
Ошибка File too large |
Абсолютный лимит WeCom на все загрузки файлов — 20 МБ. Сожмите или разделите файл. |
| Изображения отправляются как файлы | Изображения > 10 МБ превышают лимит нативного изображения и автоматически понижаются до вложений-файлов. |
Timeout sending message to WeCom |
WebSocket мог отключиться. Проверьте логи на наличие сообщений о переподключении. |
WeCom websocket closed during authentication |
Сетевая проблема или неверные учётные данные. Проверьте bot_id и secret. |