Настройка 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_IDID приложения (клиента) Azure AD
TEAMS_CLIENT_SECRETClient secret Azure AD
TEAMS_TENANT_IDID тенанта Azure AD
TEAMS_ALLOWED_USERSAAD object ID через запятую — кому разрешено пользоваться ботом
TEAMS_ALLOW_ALL_USERSЗначение true отключает список разрешений и пускает любого
TEAMS_HOME_CHANNELID диалога для доставки сообщений 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 отклоняются

Связанная документация

ESC