Настройка Microsoft Teams
Подключите Hermes Agent к Microsoft Teams в роли бота. В отличие от Socket Mode у Slack, Teams доставляет сообщения через вызов публичного HTTPS-вебхука — значит, вашему экземпляру нужна конечная точка, доступная извне. Для локальной разработки подойдёт dev-туннель, в продакшене — настоящий домен.
Нужны не обычные диалоги бота, а сводки встреч из событий Microsoft Graph? Для этого есть отдельная страница: Встречи Teams.
Запустите
hermes gateway setupи выберите Microsoft Teams — мастер проведёт вас по шагам.
Как бот отвечает
| Контекст | Поведение |
|---|---|
| Личный чат (DM) | Бот отвечает на каждое сообщение. Упоминание @ не требуется. |
| Групповой чат | Бот отвечает только при упоминании @. |
| Канал | Бот отвечает только при упоминании @. |
Упоминания @ приходят в Teams как обычные сообщения с тегами <at>BotName</at> — Hermes вырезает их автоматически перед обработкой.
Если вы устанавливаете Hermes из исходников или в режиме editable, добавьте extra teams, чтобы встроенный адаптер смог подключить Microsoft Teams SDK:
uv sync --extra teams
# или для editable-установки:
uv pip install -e ".[teams]"
Шаг 1: Установите Teams CLI
@microsoft/teams.cli автоматизирует регистрацию бота, и портал Azure для этого не нужен.
npm install -g @microsoft/teams.cli@preview
teams login
Чтобы проверить вход и узнать свой AAD object ID (он понадобится для TEAMS_ALLOWED_USERS):
teams status --verbose
Шаг 2: Откройте порт вебхука наружу
В localhost Teams сообщения доставлять не умеет. Для локальной разработки возьмите любой инструмент туннелирования и получите публичный HTTPS-URL. Порт по умолчанию — 3978, при необходимости поменяйте его через TEAMS_PORT.
# devtunnel (Microsoft)
devtunnel create hermes-bot --allow-anonymous
devtunnel port create hermes-bot -p 3978 --protocol https # замените 3978 на TEAMS_PORT, если меняли
devtunnel host hermes-bot
# ngrok
ngrok http 3978 # замените 3978 на TEAMS_PORT, если меняли
# cloudflared
cloudflared tunnel --url http://localhost:3978 # замените 3978 на TEAMS_PORT, если меняли
Скопируйте из вывода URL вида https:// — он пригодится на следующем шаге. Пока идёт разработка, туннель не закрывайте.
В продакшене вместо этого направьте конечную точку бота на публичный домен вашего сервера (см. Развёртывание в продакшене).
Шаг 3: Создайте бота
teams app create \
--name "Hermes" \
--endpoint "https://<your-tunnel-url>/api/messages"
CLI выдаст ваши CLIENT_ID, CLIENT_SECRET и TENANT_ID, а вместе с ними ссылку для установки из Шага 6. Сохраните client secret — повторно его не покажут.
Шаг 4: Задайте переменные окружения
Добавьте в ~/.hermes/.env:
# Обязательные
TEAMS_CLIENT_ID=<your-client-id>
TEAMS_CLIENT_SECRET=<your-client-secret>
TEAMS_TENANT_ID=<your-tenant-id>
# Ограничьте доступ конкретными пользователями (рекомендуется)
# Используйте AAD object ID из `teams status --verbose`
TEAMS_ALLOWED_USERS=<your-aad-object-id>
Шаг 5: Запустите шлюз
HERMES_UID=$(id -u) HERMES_GID=$(id -g) docker compose up -d gateway
Команда поднимает шлюз. Порт вебхука по умолчанию — 3978 (переопределяется через TEAMS_PORT). Проверьте, что всё работает:
curl http://localhost:3978/health # должно вернуть: ok
docker logs -f hermes
Ищите строку:
[teams] Webhook server listening on 0.0.0.0:3978/api/messages
Шаг 6: Установите приложение в Teams
teams app get <teamsAppId> --install-link
Откройте напечатанную ссылку в браузере — она ведёт прямо в клиент Teams. После установки отправьте боту личное сообщение, и он готов к работе.
Справочник по конфигурации
Переменные окружения
| Переменная | Описание |
|---|---|
TEAMS_CLIENT_ID | ID приложения (клиента) Azure AD |
TEAMS_CLIENT_SECRET | Client secret Azure AD |
TEAMS_TENANT_ID | ID тенанта Azure AD |
TEAMS_ALLOWED_USERS | AAD object ID через запятую — кому разрешено пользоваться ботом |
TEAMS_ALLOW_ALL_USERS | Значение true отключает список разрешений и пускает любого |
TEAMS_HOME_CHANNEL | ID диалога для доставки сообщений cron и проактивных уведомлений |
TEAMS_HOME_CHANNEL_NAME | Отображаемое имя домашнего канала |
TEAMS_PORT | Порт вебхука (по умолчанию: 3978) |
config.yaml
Те же настройки можно задать через ~/.hermes/config.yaml:
platforms:
teams:
enabled: true
extra:
client_id: "your-client-id"
client_secret: "your-secret"
tenant_id: "your-tenant-id"
port: 3978
Возможности
Интерактивные карточки подтверждения
Когда агенту нужно выполнить потенциально опасную команду, он не просит ввести /approve, а присылает Adaptive Card с четырьмя кнопками:
- Allow Once — разрешить именно эту команду
- Allow Session — разрешить этот шаблон до конца сессии
- Always Allow — разрешить этот шаблон навсегда
- Deny — отклонить команду
Нажатие на кнопку решает запрос прямо на месте и заменяет карточку принятым решением.
Доставка сводок встреч (конвейер встреч Teams)
Если включён плагин конвейера встреч Teams, этот же адаптер берёт на себя и исходящую отправку сводок — одна точка интеграции с Teams, а не две. После того как стенограмма встречи обобщена, писатель публикует сводку в выбранную вами цель Teams.
Доставка сводок конвейера настраивается в том же блоке платформы teams, рядом с конфигурацией бота:
platforms:
teams:
enabled: true
extra:
# существующая конфигурация бота (client_id, client_secret, tenant_id, port) ...
# Доставка сводок встреч (работает только при включённом плагине teams_pipeline)
delivery_mode: "graph" # или "incoming_webhook"
# Для delivery_mode: graph — выберите ОДНО из:
chat_id: "19:meeting_..." # публикация в чат Teams
# team_id: "..." # ИЛИ публикация в канал
# channel_id: "..."
# access_token: "..." # необязательно; иначе берутся учётные данные приложения MSGRAPH_*
# Для delivery_mode: incoming_webhook:
# incoming_webhook_url: "https://outlook.office.com/webhook/..."
| Режим | Когда выбирать | Компромисс |
|---|---|---|
incoming_webhook | Простой сценарий «опубликовать сводку в этот канал» со статическим URL, который генерирует Teams. | Нет тредов в ответах, нет реакций, отображается как заданная для вебхука личность. |
graph | Публикации в треды канала или сообщения в чаты 1:1 и групповые — под личностью бота через Microsoft Graph. | Требует регистрации приложения Graph с разрешениями уровня приложения ChannelMessage.Send (канал) или Chat.ReadWrite.All (чат). |
Когда плагин teams_pipeline не включён, эти настройки бездействуют — они подключаются лишь в момент, когда среда выполнения конвейера привязывается ко входу вебхука Graph.
Развёртывание в продакшене
Для постоянного сервера обойдитесь без devtunnel и зарегистрируйте бота с публичной HTTPS-конечной точкой вашего сервера:
teams app create \
--name "Hermes" \
--endpoint "https://your-domain.com/api/messages"
Если бот уже создан и нужно лишь обновить конечную точку:
teams app update --id <teamsAppId> --endpoint "https://your-domain.com/api/messages"
Убедитесь, что настроенный порт (TEAMS_PORT, по умолчанию 3978) доступен из интернета, а TLS-сертификат действителен: самоподписанные сертификаты Teams отвергает.
Устранение неполадок
| Проблема | Решение |
|---|---|
Эндпойнт health работает, но бот не отвечает | Проверьте, что туннель всё ещё запущен, а конечная точка сообщений бота совпадает с URL туннеля |
KeyError: 'teams' в логах | Перезапустите контейнер — в текущей версии это уже исправлено |
| Бот отвечает ошибками аутентификации | Убедитесь, что TEAMS_CLIENT_ID, TEAMS_CLIENT_SECRET и TEAMS_TENANT_ID заданы верно |
No inference provider configured | Проверьте, что ANTHROPIC_API_KEY (или ключ другого провайдера) указан в ~/.hermes/.env |
| Бот получает сообщения, но игнорирует их | Возможно, вашего AAD object ID нет в TEAMS_ALLOWED_USERS. Найдите его командой teams status --verbose |
| URL туннеля меняется при перезапуске | URL devtunnel сохраняются, если использовать именованный туннель (devtunnel create hermes-bot). ngrok и cloudflared при каждом запуске выдают новый URL, если у вас нет платного тарифа — обновляйте конечную точку бота через teams app update, когда он меняется |
| Teams показывает «This bot is not responding» | Вебхук вернул ошибку. Поищите трассировки в docker logs hermes |
[teams] Failed to connect в логах | SDK не смог пройти аутентификацию. Перепроверьте учётные данные и то, что tenant ID совпадает с аккаунтом, под которым вы выполнили teams login |
Безопасность
Всегда задавайте TEAMS_ALLOWED_USERS с AAD object ID авторизованных пользователей. Без этого с ботом сможет взаимодействовать любой, кто найдёт или установит его.
Относитесь к TEAMS_CLIENT_SECRET как к паролю и периодически меняйте его через портал Azure или Teams CLI.
- Храните учётные данные в
~/.hermes/.envс правами600(chmod 600 ~/.hermes/.env) - Бот принимает сообщения только от пользователей из
TEAMS_ALLOWED_USERS; неавторизованные сообщения молча отбрасываются - Ваша публичная конечная точка (
/api/messages) защищена Teams Bot Framework — запросы без валидных JWT отклоняются