Microsoft Teams
«Оставь надежду, всяк сюда входящий.»
Обновлено: 2026-01-21 Статус: поддерживаются текст и вложения в ЛС; отправка файлов в каналах/группах требует sharePointSiteId + разрешений Graph (см. Отправка файлов в групповых чатах). Опросы отправляются через Adaptive Cards.
Требуется плагин
Microsoft Teams поставляется в виде плагина и не входит в базовую установку. Критическое изменение (2026.1.15): MS Teams вынесен из ядра. Если вы его используете, необходимо установить плагин. Объяснение: делает базовые установки легче и позволяет зависимостям MS Teams обновляться независимо. Установка через CLI (npm registry):
openclaw plugins install @openclaw/msteams
Локальная установка из репозитория (при запуске из git-репозитория):
openclaw plugins install ./extensions/msteams
Если вы выберете Teams во время настройки/первого запуска и будет обнаружен git-репозиторий, OpenClaw автоматически предложит путь для локальной установки. Подробности: Плагины
Быстрая настройка (для начинающих)
- Установите плагин Microsoft Teams.
- Создайте Azure Bot (App ID + client secret + tenant ID).
- Настройте OpenClaw с этими учетными данными.
- Откройте доступ к
/api/messages(по умолчанию порт 3978) через публичный URL или туннель. - Установите пакет приложения Teams и запустите шлюз.
Минимальная конфигурация:
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
appPassword: "<APP_PASSWORD>",
tenantId: "<TENANT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Примечание: групповые чаты по умолчанию заблокированы (channels.msteams.groupPolicy: "allowlist"). Чтобы разрешить ответы в группах, установите channels.msteams.groupAllowFrom (или используйте groupPolicy: "open" для разрешения любому участнику, с требованием упоминания).
Цели
- Общаться с OpenClaw через ЛС, групповые чаты или каналы Teams.
- Сохранять детерминированную маршрутизацию: ответы всегда возвращаются в тот канал, откуда пришло сообщение.
- По умолчанию использовать безопасное поведение для каналов (требуется упоминание, если не настроено иначе).
Запись в конфигурацию
По умолчанию Microsoft Teams разрешено записывать обновления конфигурации, вызванные командой /config set|unset (требуется commands.config: true). Отключить можно так:
{
channels: { msteams: { configWrites: false } },
}
Контроль доступа (ЛС + группы)
Доступ в ЛС
- По умолчанию:
channels.msteams.dmPolicy = "pairing". Неизвестные отправители игнорируются до одобрения. channels.msteams.allowFromдолжен использовать стабильные AAD object IDs.- UPNs/отображаемые имена изменяемы; прямое сопоставление по умолчанию отключено и включается только с
channels.msteams.dangerouslyAllowNameMatching: true. - Мастер настройки может разрешать имена в ID через Microsoft Graph, когда учетные данные это позволяют.
Доступ в группах
- По умолчанию:
channels.msteams.groupPolicy = "allowlist"(заблокировано, пока вы не добавитеgroupAllowFrom). Используйтеchannels.defaults.groupPolicy, чтобы переопределить значение по умолчанию, если оно не задано. channels.msteams.groupAllowFromуправляет тем, какие отправители могут активировать бота в групповых чатах/каналах (возвращается кchannels.msteams.allowFrom).- Установите
groupPolicy: "open", чтобы разрешить любому участнику (по умолчанию всё равно требуется упоминание). - Чтобы запретить все каналы, установите
channels.msteams.groupPolicy: "disabled".
Пример:
{
channels: {
msteams: {
groupPolicy: "allowlist",
groupAllowFrom: ["user@org.com"],
},
},
}
Разрешительный список команд и каналов
- Ограничьте ответы в группах/каналах, перечислив команды и каналы в
channels.msteams.teams. - Ключами могут быть ID команд или их имена; ключи каналов — ID бесед или имена.
- Когда
groupPolicy="allowlist"и присутствует разрешительный список команд, принимаются только перечисленные команды/каналы (с требованием упоминания). - Мастер настройки принимает записи вида
Команда/Канали сохраняет их для вас. - При запуске OpenClaw разрешает имена команд/каналов и пользователей в ID (когда разрешения Graph позволяют) и логирует сопоставление; неразрешенные записи сохраняются как введенные.
Пример:
{
channels: {
msteams: {
groupPolicy: "allowlist",
teams: {
"Моя команда": {
channels: {
Общий: { requireMention: true },
},
},
},
},
},
}
Как это работает
- Установите плагин Microsoft Teams.
- Создайте Azure Bot (App ID + secret + tenant ID).
- Соберите пакет приложения Teams, который ссылается на бота и включает разрешения RSC, указанные ниже.
- Загрузите/установите приложение Teams в команду (или в личную область для ЛС).
- Настройте
msteamsв~/.openclaw/openclaw.json(или переменных окружения) и запустите шлюз. - Шлюз прослушивает трафик вебхуков Bot Framework на
/api/messagesпо умолчанию.
Настройка Azure Bot (Предварительные требования)
Перед настройкой OpenClaw необходимо создать ресурс Azure Bot.
Шаг 1: Создание Azure Bot
-
Перейдите на страницу Создание Azure Bot
-
Заполните вкладку Основные:
Поле Значение Имя бота Имя вашего бота, например, openclaw-msteams(должно быть уникальным)Подписка Выберите вашу подписку Azure Группа ресурсов Создайте новую или используйте существующую Ценовая категория Бесплатный для разработки/тестирования Тип приложения Один клиент (рекомендуется — см. примечание ниже) Тип создания Создать новый идентификатор приложения Microsoft
Уведомление об устаревании: Создание новых мультитенантных ботов было прекращено после 2025-07-31. Используйте Один клиент для новых ботов.
- Нажмите Просмотр и создание → Создать (подождите ~1-2 минуты)
Шаг 2: Получение учетных данных
- Перейдите в ресурс Azure Bot → Конфигурация
- Скопируйте Идентификатор приложения Microsoft → это ваш
appId - Нажмите Управление паролем → перейдите в Регистрацию приложения
- В разделе Сертификаты и секреты → Новый секрет клиента → скопируйте Значение → это ваш
appPassword - Перейдите в Обзор → скопируйте Идентификатор каталога (клиента) → это ваш
tenantId
Шаг 3: Настройка конечной точки обмена сообщениями
- В Azure Bot → Конфигурация
- Установите Конечная точка обмена сообщениями на URL вашего вебхука:
- Продакшен:
https://ваш-домен.com/api/messages - Локальная разработка: Используйте туннель (см. Локальная разработка (туннелирование) ниже)
- Продакшен:
Шаг 4: Включение канала Teams
- В Azure Bot → Каналы
- Нажмите Microsoft Teams → Настроить → Сохранить
- Примите Условия использования
Локальная разработка (Туннелирование)
Teams не может обращаться к localhost. Используйте туннель для локальной разработки: Вариант A: ngrok
ngrok http 3978
# Скопируйте HTTPS URL, например, https://abc123.ngrok.io
# Установите конечную точку обмена сообщениями: https://abc123.ngrok.io/api/messages
Вариант B: Tailscale Funnel
tailscale funnel 3978
# Используйте ваш Tailscale funnel URL как конечную точку обмена сообщениями
Портал разработчика Teams (Альтернатива)
Вместо ручного создания ZIP-манифеста можно использовать Портал разработчика Teams:
- Нажмите + Новое приложение
- Заполните основную информацию (имя, описание, информация о разработчике)
- Перейдите в Возможности приложения → Бот
- Выберите Ввести идентификатор бота вручную и вставьте App ID вашего Azure Bot
- Отметьте области: Личное, Команда, Групповой чат
- Нажмите Распространение → Скачать пакет приложения
- В Teams: Приложения → Управление вашими приложениями → Загрузить пользовательское приложение → выберите ZIP
Это часто проще, чем ручное редактирование JSON-манифестов.
Тестирование бота
Вариант A: Веб-чат Azure (сначала проверьте вебхук)
- На портале Azure → ваш ресурс Azure Bot → Тестировать в веб-чате
- Отправьте сообщение — вы должны увидеть ответ
- Это подтверждает, что конечная точка вебхука работает перед настройкой Teams
Вариант B: Teams (после установки приложения)
- Установите приложение Teams (сайдлоад или каталог организации)
- Найдите бота в Teams и отправьте ЛС
- Проверьте логи шлюза на входящие активности
Настройка (минимальная, только текст)
-
Установите плагин Microsoft Teams
- Из npm:
openclaw plugins install @openclaw/msteams - Из локального репозитория:
openclaw plugins install ./extensions/msteams
- Из npm:
-
Регистрация бота
- Создайте Azure Bot (см. выше) и запишите:
- App ID
- Секрет клиента (Пароль приложения)
- Tenant ID (один клиент)
- Создайте Azure Bot (см. выше) и запишите:
-
Манифест приложения Teams
- Включите запись
botсbotId = <App ID>. - Области:
personal,team,groupChat. supportsFiles: true(требуется для обработки файлов в личной области).- Добавьте разрешения RSC (ниже).
- Создайте иконки:
outline.png(32x32) иcolor.png(192x192). - Заархивируйте все три файла вместе:
manifest.json,outline.png,color.png.
- Включите запись
-
Настройте OpenClaw
Копировать
{ "msteams": { "enabled": true, "appId": "<APP_ID>", "appPassword": "<APP_PASSWORD>", "tenantId": "<TENANT_ID>", "webhook": { "port": 3978, "path": "/api/messages" } } }Вы также можете использовать переменные окружения вместо ключей конфигурации:
MSTEAMS_APP_IDMSTEAMS_APP_PASSWORDMSTEAMS_TENANT_ID
-
Конечная точка бота
- Установите Конечную точку обмена сообщениями Azure Bot на:
https://<хост>:3978/api/messages(или выбранный вами путь/порт).
- Установите Конечную точку обмена сообщениями Azure Bot на:
-
Запустите шлюз
- Канал Teams запускается автоматически, когда плагин установлен и существует конфигурация
msteamsс учетными данными.
- Канал Teams запускается автоматически, когда плагин установлен и существует конфигурация
Контекст истории
channels.msteams.historyLimitконтролирует, сколько последних сообщений канала/группы будет включено в промпт.- Возвращается к
messages.groupChat.historyLimit. Установите0для отключения (по умолчанию 50). - История ЛС может быть ограничена с помощью
channels.msteams.dmHistoryLimit(ходы пользователя). Переопределения для конкретного пользователя:channels.msteams.dms["<user_id>"].historyLimit.
Текущие разрешения RSC для Teams (Манифест)
Это существующие разрешения resourceSpecific в нашем манифесте приложения Teams. Они применяются только внутри команды/чата, где установлено приложение. Для каналов (область команды):
ChannelMessage.Read.Group(Application) — получать все сообщения канала без @упоминанияChannelMessage.Send.Group(Application)Member.Read.Group(Application)Owner.Read.Group(Application)ChannelSettings.Read.Group(Application)TeamMember.Read.Group(Application)TeamSettings.Read.Group(Application)
Для групповых чатов:
ChatMessage.Read.Chat(Application) — получать все сообщения группового чата без @упоминания
Пример манифеста Teams (сокращенный)
Минимальный, рабочий пример с обязательными полями. Замените ID и URL.
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.23/MicrosoftTeams.schema.json",
"manifestVersion": "1.23",
"version": "1.0.0",
"id": "00000000-0000-0000-0000-000000000000",
"name": { "short": "OpenClaw" },
"developer": {
"name": "Ваша организация",
"websiteUrl": "https://example.com",
"privacyUrl": "https://example.com/privacy",
"termsOfUseUrl": "https://example.com/terms"
},
"description": { "short": "OpenClaw в Teams", "full": "OpenClaw в Teams" },
"icons": { "outline": "outline.png", "color": "color.png" },
"accentColor": "#5B6DEF",
"bots": [
{
"botId": "11111111-1111-1111-1111-111111111111",
"scopes": ["personal", "team", "groupChat"],
"isNotificationOnly": false,
"supportsCalling": false,
"supportsVideo": false,
"supportsFiles": true
}
],
"webApplicationInfo": {
"id": "11111111-1111-1111-1111-111111111111"
},
"authorization": {
"permissions": {
"resourceSpecific": [
{ "name": "ChannelMessage.Read.Group", "type": "Application" },
{ "name": "ChannelMessage.Send.Group", "type": "Application" },
{ "name": "Member.Read.Group", "type": "Application" },
{ "name": "Owner.Read.Group", "type": "Application" },
{ "name": "ChannelSettings.Read.Group", "type": "Application" },
{ "name": "TeamMember.Read.Group", "type": "Application" },
{ "name": "TeamSettings.Read.Group", "type": "Application" },
{ "name": "ChatMessage.Read.Chat", "type": "Application" }
]
}
}
}
Особенности манифеста (обязательные поля)
bots[].botIdдолжен совпадать с App ID Azure Bot.webApplicationInfo.idдолжен совпадать с App ID Azure Bot.bots[].scopesдолжен включать области, которые вы планируете использовать (personal,team,groupChat).bots[].supportsFiles: trueтребуется для обработки файлов в личной области.authorization.permissions.resourceSpecificдолжен включать чтение/отправку каналов, если вам нужен трафик каналов.
Обновление существующего приложения
Чтобы обновить уже установленное приложение Teams (например, добавить разрешения RSC):
- Обновите ваш
manifest.jsonс новыми настройками - Увеличьте поле
version(например,1.0.0→1.1.0) - Перезаархивируйте манифест с иконками (
manifest.json,outline.png,color.png) - Загрузите новый zip:
- Вариант A (Центр администрирования Teams): Центр администрирования Teams → Приложения Teams → Управление приложениями → найдите ваше приложение → Загрузить новую версию
- Вариант B (Сайдлоад): В Teams → Приложения → Управление вашими приложениями → Загрузить пользовательское приложение
- Для каналов команд: Переустановите приложение в каждой команде, чтобы новые разрешения вступили в силу
- Полностью закройте и перезапустите Teams (не просто закройте окно), чтобы очистить кэшированные метаданные приложения
Возможности: только RSC vs Graph
Только с Teams RSC (приложение установлено, без разрешений Graph API)
Работает:
- Чтение текстового содержимого сообщений канала.
- Отправка текстового содержимого сообщений канала.
- Получение вложений файлов в личных сообщениях (ЛС).
Не работает:
- Содержимое изображений или файлов в каналах/группах (в полезной нагрузке только HTML-заглушка).
- Загрузка вложений, хранящихся в SharePoint/OneDrive.
- Чтение истории сообщений (помимо живого события вебхука).
С Teams RSC + разрешениями приложения Microsoft Graph
Добавляет:
- Загрузка размещенного содержимого (изображений, вставленных в сообщения).
- Загрузка вложений файлов, хранящихся в SharePoint/OneDrive.
- Чтение истории сообщений канала/чата через Graph.
RSC vs Graph API
| Возможность | Разрешения RSC | Graph API |
|---|---|---|
| Сообщения в реальном времени | Да (через вебхук) | Нет (только опрос) |
| Исторические сообщения | Нет | Да (можно запрашивать историю) |
| Сложность настройки | Только манифест приложения | Требует согласия администратора + поток токенов |
| Работает офлайн | Нет (должен быть запущен) | Да (запрос в любое время) |
Итог: RSC предназначен для прослушивания в реальном времени; Graph API — для доступа к истории. Для обработки пропущенных сообщений в офлайне вам нужен Graph API с ChannelMessage.Read.All (требует согласия администратора).
Медиа и история с Graph (требуется для каналов)
Если вам нужны изображения/файлы в каналах или вы хотите получать историю сообщений, необходимо включить разрешения Microsoft Graph и предоставить согласие администратора.
- В Entra ID (Azure AD) Регистрация приложения добавьте Разрешения приложения Microsoft Graph:
ChannelMessage.Read.All(вложения канала + история)Chat.Read.AllилиChatMessage.Read.All(групповые чаты)
- Предоставьте согласие администратора для клиента.
- Увеличьте версию манифеста приложения Teams, перезагрузите и переустановите приложение в Teams.
- Полностью закройте и перезапустите Teams, чтобы очистить кэшированные метаданные приложения.
Дополнительное разрешение для упоминаний пользователей: Упоминания пользователей через @ работают из коробки для пользователей в беседе. Однако, если вы хотите динамически искать и упоминать пользователей, которые не находятся в текущей беседе, добавьте разрешение User.Read.All (Application) и предоставьте согласие администратора.
Известные ограничения
Таймауты вебхука
Teams доставляет сообщения через HTTP вебхук. Если обработка занимает слишком много времени (например, медленные ответы LLM), вы можете столкнуться с:
- Таймаутами шлюза
- Повторными попытками отправки сообщения Teams (вызывает дубликаты)
- Потерянными ответами
OpenClaw обрабатывает это, быстро возвращая ответ и отправляя ответы проактивно, но очень медленные ответы всё равно могут вызывать проблемы.
Форматирование
Markdown в Teams более ограничен, чем в Slack или Discord:
- Базовое форматирование работает: жирный, курсив,
код, ссылки - Сложный markdown (таблицы, вложенные списки) может отображаться некорректно
- Adaptive Cards поддерживаются для опросов и произвольной отправки карточек (см. ниже)
Конфигурация
Ключевые настройки (см. /gateway/configuration для общих шаблонов каналов):
channels.msteams.enabled: включить/отключить канал.channels.msteams.appId,channels.msteams.appPassword,channels.msteams.tenantId: учетные данные бота.channels.msteams.webhook.port(по умолчанию3978)channels.msteams.webhook.path(по умолчанию/api/messages)channels.msteams.dmPolicy:pairing | allowlist | open | disabled(по умолчанию: pairing)channels.msteams.allowFrom: разрешительный список для ЛС (рекомендуются AAD object IDs). Мастер настройки разрешает имена в ID во время установки, когда доступен Graph.channels.msteams.dangerouslyAllowNameMatching: аварийный переключатель для повторного включения сопоставления по изменяемым UPN/отображаемым именам.channels.msteams.textChunkLimit: размер фрагмента исходящего текста.channels.msteams.chunkMode:length(по умолчанию) илиnewlineдля разделения по пустым строкам (границам абзацев) перед разделением по длине.channels.msteams.mediaAllowHosts: разрешительный список хостов для входящих вложений (по умолчанию домены Microsoft/Teams).channels.msteams.mediaAuthAllowHosts: разрешительный список для добавления заголовков Authorization при повторных попытках загрузки медиа (по умолчанию хосты Graph + Bot Framework).channels.msteams.requireMention: требовать @упоминание в каналах/группах (по умолчанию true).channels.msteams.replyStyle:thread | top-level(см. Стиль ответа: ветки vs записи).channels.msteams.teams.<teamId>.replyStyle: переопределение для конкретной команды.channels.msteams.teams.<teamId>.requireMention: переопределение для конкретной команды.channels.msteams.teams.<teamId>.tools: переопределения политики инструментов по умолчанию для команды (allow/deny/alsoAllow), используемые, когда отсутствует переопределение для канала.channels.msteams.teams.<teamId>.toolsBySender: переопределения политики инструментов по умолчанию для команды для конкретного отправителя (поддерживается wildcard"*").channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle: переопределение для конкретного канала.channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention: переопределение для конкретного канала.channels.msteams.teams.<teamId>.channels.<conversationId>.tools: переопределения политики инструментов для конкретного канала (allow/deny/alsoAllow).channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender: переопределения политики инструментов для конкретного канала для конкретного отправителя (поддерживается wildcard"*").- Ключи
toolsBySenderдолжны использовать явные префиксы:id:,e164:,username:,name:(устаревшие ключи без префикса всё ещё сопоставляются только сid:). channels.msteams.sharePointSiteId: ID сайта SharePoint для загрузки файлов в групповых чатах/каналах (см. Отправка файлов в групповых чатах).
Маршрутизация и сессии
- Ключи сессий следуют стандартному формату агента (см. /concepts/session):
- Прямые сообщения используют основную сессию (
agent:<agentId>:<mainKey>). - Сообщения канала/группы используют ID беседы:
agent:<agentId>:msteams:channel:<conversationId>agent:<agentId>:msteams:group:<conversationId>
- Прямые сообщения используют основную сессию (
Стиль ответа: Ветки vs Записи
Teams недавно представили два стиля интерфейса канала поверх одной и той же базовой модели данных:
| Стиль | Описание | Рекомендуемый replyStyle |
|---|---|---|
| Записи (классический) | Сообщения отображаются как карточки с ответами в ветке под ними | thread (по умолчанию) |
| Ветки (похоже на Slack) | Сообщения идут линейно, больше похоже на Slack | top-level |
Проблема: API Teams не раскрывает, какой стиль интерфейса использует канал. Если использовать неправильный replyStyle:
threadв канале со стилем Ветки → ответы появляются неудобно вложеннымиtop-levelв канале со стилем Записей → ответы появляются как отдельные записи верхнего уровня вместо ответов в ветке
Решение: Настройте replyStyle для каждого канала в зависимости от его настройки:
{
"msteams": {
"replyStyle": "thread",
"teams": {
"19:abc...@thread.tacv2": {
"channels": {
"19:xyz...@thread.tacv2": {
"replyStyle": "top-level"
}
}
}
}
}
}
Вложения и изображения
Текущие ограничения:
- ЛС: Изображения и вложения файлов работают через API файлов бота Teams.
- Каналы/группы: Вложения хранятся в хранилище M365 (SharePoint/OneDrive). Полезная нагрузка вебхука содержит только HTML-заглушку, а не сами байты файла. Для загрузки вложений канала требуются разрешения Graph API.
Без разрешений Graph сообщения канала с изображениями будут получены как только текст (содержимое изображения недоступно для бота). По умолчанию OpenClaw загружает медиа только с хостов Microsoft/Teams. Переопределите с помощью channels.msteams.mediaAllowHosts (используйте ["*"], чтобы разрешить любой хост). Заголовки Authorization добавляются только для хостов в channels.msteams.mediaAuthAllowHosts (по умолчанию хосты Graph + Bot Framework). Держите этот список строгим (избегайте мультитенантных суффиксов).
Отправка файлов в групповых чатах
Боты могут отправлять файлы в ЛС, используя поток FileConsentCard (встроенный). Однако отправка файлов в групповых чатах/каналах требует дополнительной настройки:
| Контекст | Как отправляются файлы | Требуемая настройка |
|---|---|---|
| ЛС | FileConsentCard → пользователь принимает → бот загружает | Работает из коробки |
| Групповые чаты/каналы | Загрузка в SharePoint → ссылка для общего доступа | Требуется sharePointSiteId + разрешения Graph |
| Изображения (любой контекст) | Встроенные, закодированные в Base64 | Работает из коробки |
Почему групповым чатам нужен SharePoint
У ботов нет личного диска OneDrive (конечная точка Graph API /me/drive не работает для удостоверений приложения). Чтобы отправлять файлы в групповых чатах/каналах, бот загружает их на сайт SharePoint и создает ссылку для общего доступа.
Настройка
-
Добавьте разрешения Graph API в Entra ID (Azure AD) → Регистрация приложения:
Sites.ReadWrite.All(Application) — загружать файлы в SharePointChat.Read.All(Application) — опционально, включает ссылки для общего доступа для конкретного пользователя
-
Предоставьте согласие администратора для клиента.
-
Получите ID вашего сайта SharePoint:
Копировать
# Через Graph Explorer или curl с валидным токеном: curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}" # Пример: для сайта "contoso.sharepoint.com/sites/BotFiles" curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com