Платформы обмена сообщениями

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 автоматически предложит путь для локальной установки. Подробности: Плагины

Быстрая настройка (для начинающих)

  1. Установите плагин Microsoft Teams.
  2. Создайте Azure Bot (App ID + client secret + tenant ID).
  3. Настройте OpenClaw с этими учетными данными.
  4. Откройте доступ к /api/messages (по умолчанию порт 3978) через публичный URL или туннель.
  5. Установите пакет приложения 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 },
          },
        },
      },
    },
  },
}

Как это работает

  1. Установите плагин Microsoft Teams.
  2. Создайте Azure Bot (App ID + secret + tenant ID).
  3. Соберите пакет приложения Teams, который ссылается на бота и включает разрешения RSC, указанные ниже.
  4. Загрузите/установите приложение Teams в команду (или в личную область для ЛС).
  5. Настройте msteams в ~/.openclaw/openclaw.json (или переменных окружения) и запустите шлюз.
  6. Шлюз прослушивает трафик вебхуков Bot Framework на /api/messages по умолчанию.

Настройка Azure Bot (Предварительные требования)

Перед настройкой OpenClaw необходимо создать ресурс Azure Bot.

Шаг 1: Создание Azure Bot

  1. Перейдите на страницу Создание Azure Bot

  2. Заполните вкладку Основные:

    ПолеЗначение
    Имя ботаИмя вашего бота, например, openclaw-msteams (должно быть уникальным)
    ПодпискаВыберите вашу подписку Azure
    Группа ресурсовСоздайте новую или используйте существующую
    Ценовая категорияБесплатный для разработки/тестирования
    Тип приложенияОдин клиент (рекомендуется — см. примечание ниже)
    Тип созданияСоздать новый идентификатор приложения Microsoft

Уведомление об устаревании: Создание новых мультитенантных ботов было прекращено после 2025-07-31. Используйте Один клиент для новых ботов.

  1. Нажмите Просмотр и созданиеСоздать (подождите ~1-2 минуты)

Шаг 2: Получение учетных данных

  1. Перейдите в ресурс Azure Bot → Конфигурация
  2. Скопируйте Идентификатор приложения Microsoft → это ваш appId
  3. Нажмите Управление паролем → перейдите в Регистрацию приложения
  4. В разделе Сертификаты и секретыНовый секрет клиента → скопируйте Значение → это ваш appPassword
  5. Перейдите в Обзор → скопируйте Идентификатор каталога (клиента) → это ваш tenantId

Шаг 3: Настройка конечной точки обмена сообщениями

  1. В Azure Bot → Конфигурация
  2. Установите Конечная точка обмена сообщениями на URL вашего вебхука:

Шаг 4: Включение канала Teams

  1. В Azure Bot → Каналы
  2. Нажмите Microsoft Teams → Настроить → Сохранить
  3. Примите Условия использования

Локальная разработка (Туннелирование)

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:

  1. Нажмите + Новое приложение
  2. Заполните основную информацию (имя, описание, информация о разработчике)
  3. Перейдите в Возможности приложенияБот
  4. Выберите Ввести идентификатор бота вручную и вставьте App ID вашего Azure Bot
  5. Отметьте области: Личное, Команда, Групповой чат
  6. Нажмите РаспространениеСкачать пакет приложения
  7. В Teams: ПриложенияУправление вашими приложениямиЗагрузить пользовательское приложение → выберите ZIP

Это часто проще, чем ручное редактирование JSON-манифестов.

Тестирование бота

Вариант A: Веб-чат Azure (сначала проверьте вебхук)

  1. На портале Azure → ваш ресурс Azure Bot → Тестировать в веб-чате
  2. Отправьте сообщение — вы должны увидеть ответ
  3. Это подтверждает, что конечная точка вебхука работает перед настройкой Teams

Вариант B: Teams (после установки приложения)

  1. Установите приложение Teams (сайдлоад или каталог организации)
  2. Найдите бота в Teams и отправьте ЛС
  3. Проверьте логи шлюза на входящие активности

Настройка (минимальная, только текст)

  1. Установите плагин Microsoft Teams

    • Из npm: openclaw plugins install @openclaw/msteams
    • Из локального репозитория: openclaw plugins install ./extensions/msteams
  2. Регистрация бота

    • Создайте Azure Bot (см. выше) и запишите:
      • App ID
      • Секрет клиента (Пароль приложения)
      • Tenant ID (один клиент)
  3. Манифест приложения Teams

    • Включите запись bot с botId = <App ID>.
    • Области: personal, team, groupChat.
    • supportsFiles: true (требуется для обработки файлов в личной области).
    • Добавьте разрешения RSC (ниже).
    • Создайте иконки: outline.png (32x32) и color.png (192x192).
    • Заархивируйте все три файла вместе: manifest.json, outline.png, color.png.
  4. Настройте OpenClaw

    Копировать

    {
      "msteams": {
        "enabled": true,
        "appId": "<APP_ID>",
        "appPassword": "<APP_PASSWORD>",
        "tenantId": "<TENANT_ID>",
        "webhook": { "port": 3978, "path": "/api/messages" }
      }
    }
    

    Вы также можете использовать переменные окружения вместо ключей конфигурации:

    • MSTEAMS_APP_ID
    • MSTEAMS_APP_PASSWORD
    • MSTEAMS_TENANT_ID
  5. Конечная точка бота

    • Установите Конечную точку обмена сообщениями Azure Bot на:
      • https://<хост>:3978/api/messages (или выбранный вами путь/порт).
  6. Запустите шлюз

    • Канал Teams запускается автоматически, когда плагин установлен и существует конфигурация msteams с учетными данными.

Контекст истории

  • 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):

  1. Обновите ваш manifest.json с новыми настройками
  2. Увеличьте поле version (например, 1.0.01.1.0)
  3. Перезаархивируйте манифест с иконками (manifest.json, outline.png, color.png)
  4. Загрузите новый zip:
    • Вариант A (Центр администрирования Teams): Центр администрирования Teams → Приложения Teams → Управление приложениями → найдите ваше приложение → Загрузить новую версию
    • Вариант B (Сайдлоад): В Teams → Приложения → Управление вашими приложениями → Загрузить пользовательское приложение
  5. Для каналов команд: Переустановите приложение в каждой команде, чтобы новые разрешения вступили в силу
  6. Полностью закройте и перезапустите Teams (не просто закройте окно), чтобы очистить кэшированные метаданные приложения

Возможности: только RSC vs Graph

Только с Teams RSC (приложение установлено, без разрешений Graph API)

Работает:

  • Чтение текстового содержимого сообщений канала.
  • Отправка текстового содержимого сообщений канала.
  • Получение вложений файлов в личных сообщениях (ЛС).

Не работает:

  • Содержимое изображений или файлов в каналах/группах (в полезной нагрузке только HTML-заглушка).
  • Загрузка вложений, хранящихся в SharePoint/OneDrive.
  • Чтение истории сообщений (помимо живого события вебхука).

С Teams RSC + разрешениями приложения Microsoft Graph

Добавляет:

  • Загрузка размещенного содержимого (изображений, вставленных в сообщения).
  • Загрузка вложений файлов, хранящихся в SharePoint/OneDrive.
  • Чтение истории сообщений канала/чата через Graph.

RSC vs Graph API

ВозможностьРазрешения RSCGraph API
Сообщения в реальном времениДа (через вебхук)Нет (только опрос)
Исторические сообщенияНетДа (можно запрашивать историю)
Сложность настройкиТолько манифест приложенияТребует согласия администратора + поток токенов
Работает офлайнНет (должен быть запущен)Да (запрос в любое время)

Итог: RSC предназначен для прослушивания в реальном времени; Graph API — для доступа к истории. Для обработки пропущенных сообщений в офлайне вам нужен Graph API с ChannelMessage.Read.All (требует согласия администратора).

Медиа и история с Graph (требуется для каналов)

Если вам нужны изображения/файлы в каналах или вы хотите получать историю сообщений, необходимо включить разрешения Microsoft Graph и предоставить согласие администратора.

  1. В Entra ID (Azure AD) Регистрация приложения добавьте Разрешения приложения Microsoft Graph:
    • ChannelMessage.Read.All (вложения канала + история)
    • Chat.Read.All или ChatMessage.Read.All (групповые чаты)
  2. Предоставьте согласие администратора для клиента.
  3. Увеличьте версию манифеста приложения Teams, перезагрузите и переустановите приложение в Teams.
  4. Полностью закройте и перезапустите 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)Сообщения идут линейно, больше похоже на Slacktop-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 и создает ссылку для общего доступа.

Настройка

  1. Добавьте разрешения Graph API в Entra ID (Azure AD) → Регистрация приложения:

    • Sites.ReadWrite.All (Application) — загружать файлы в SharePoint
    • Chat.Read.All (Application) — опционально, включает ссылки для общего доступа для конкретного пользователя
  2. Предоставьте согласие администратора для клиента.

  3. Получите 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