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 ID.
  • UPN/отображаемые имена изменяемы; прямое сопоставление отключено по умолчанию и включается только через 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: ["[email protected]"],
    },
  },
}

Allowlist команд и каналов

  • Ограничьте ответы в группах/каналах, перечисляя команды и каналы в channels.msteams.teams.
  • Ключи должны использовать стабильные ID команд и conversation ID каналов.
  • При groupPolicy="allowlist" и наличии allowlist команд принимаются только указанные команды/каналы (с требованием упоминания).
  • Мастер настройки принимает записи Team/Channel и сохраняет их.
  • При запуске OpenClaw разрешает имена команд/каналов и allowlist пользователей в ID (при наличии разрешений Graph) и логирует маппинг; неразрешённые имена сохраняются как есть, но игнорируются при маршрутизации по умолчанию, если не включён channels.msteams.dangerouslyAllowNameMatching: true.

Пример:

{
  channels: {
    msteams: {
      groupPolicy: "allowlist",
      teams: {
        "My Team": {
          channels: {
            General: { 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 webhook на /api/messages по умолчанию.

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

Перед настройкой OpenClaw нужно создать ресурс Azure Bot.

Шаг 1: Создайте Azure Bot

  1. Перейдите на Create Azure Bot

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

    ПолеЗначение
    Bot handleИмя бота, напр. openclaw-msteams (должно быть уникальным)
    SubscriptionВыберите подписку Azure
    Resource groupСоздайте новую или используйте существующую
    Pricing tierFree для разработки/тестирования
    Type of AppSingle Tenant (рекомендуется — см. примечание ниже)
    Creation typeCreate new Microsoft App ID

Примечание: Создание новых мультитенантных ботов устарело после 2025-07-31. Для новых ботов используйте Single Tenant.

  1. Нажмите Review + createCreate (подождите ~1-2 минуты)

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

  1. Перейдите к ресурсу Azure Bot → Configuration
  2. Скопируйте Microsoft App ID → это ваш appId
  3. Нажмите Manage Password → перейдите в App Registration
  4. В разделе Certificates & secretsNew client secret → скопируйте Value → это ваш appPassword
  5. Перейдите в Overview → скопируйте Directory (tenant) ID → это ваш tenantId

Шаг 3: Настройте Messaging Endpoint

  1. В Azure Bot → Configuration
  2. Установите Messaging endpoint на URL вашего webhook:

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

  1. В Azure Bot → Channels
  2. Нажмите Microsoft Teams → Configure → Save
  3. Примите условия использования

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

Teams не может обратиться к localhost. Используйте туннель для локальной разработки:

Вариант A: ngrok

ngrok http 3978
# Скопируйте HTTPS URL, напр. https://abc123.ngrok.io
# Установите messaging endpoint: https://abc123.ngrok.io/api/messages

Вариант B: Tailscale Funnel

tailscale funnel 3978
# Используйте URL Tailscale funnel как messaging endpoint

Teams Developer Portal (альтернативный способ)

Вместо ручного создания ZIP-манифеста можно использовать Teams Developer Portal:

  1. Нажмите + New app
  2. Заполните основную информацию (имя, описание, данные разработчика)
  3. Перейдите в App featuresBot
  4. Выберите Enter a bot ID manually и вставьте Azure Bot App ID
  5. Отметьте области: Personal, Team, Group Chat
  6. Нажмите DistributeDownload app package
  7. В Teams: AppsManage your appsUpload a custom app → выберите ZIP

Часто это проще, чем редактировать JSON-манифесты вручную.

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

Вариант A: Azure Web Chat (проверка webhook)

  1. В Azure Portal → ресурс Azure Bot → Test in Web Chat
  2. Отправьте сообщение — должен прийти ответ
  3. Это подтверждает работоспособность webhook-эндпоинта до настройки Teams

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

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

Установка (минимальная, только текст)

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

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

    • Создайте Azure Bot (см. выше) и запишите:
      • App ID
      • Client secret (App password)
      • Tenant ID (single-tenant)
  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 Messaging Endpoint на:
      • https://<host>: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-приложения. Они действуют только в команде/чате, где установлено приложение.

Для каналов (область team):

  • 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": "Your Org",
    "websiteUrl": "https://example.com",
    "privacyUrl": "https://example.com/privacy",
    "termsOfUseUrl": "https://example.com/terms"
  },
  "description": { "short": "OpenClaw in Teams", "full": "OpenClaw in 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 должен совпадать с Azure Bot App ID.
  • webApplicationInfo.id должен совпадать с Azure Bot App ID.
  • bots[].scopes должен содержать поверхности, которые вы планируете использовать (personal, team, groupChat).
  • bots[].supportsFiles: true обязателен для работы с файлами в персональной области.
  • authorization.permissions.resourceSpecific должен содержать channel read/send, если вам нужен трафик каналов.

Обновление существующего приложения

Для обновления уже установленного Teams-приложения (например, добавления RSC-разрешений):

  1. Обновите manifest.json с новыми настройками
  2. Увеличьте поле version (напр. 1.0.01.1.0)
  3. Заново заархивируйте манифест с иконками (manifest.json, outline.png, color.png)
  4. Загрузите новый ZIP:
    • Вариант A (Teams Admin Center): Teams Admin Center → Teams apps → Manage apps → найдите приложение → Upload new version
    • Вариант B (Sideload): В Teams → Apps → Manage your apps → Upload a custom app
  5. Для каналов команд: переустановите приложение в каждой команде для применения новых разрешений
  6. Полностью закройте и перезапустите Teams (не просто закройте окно), чтобы очистить кэшированные метаданные приложения

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

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

Работает:

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

Не работает:

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

Teams RSC + разрешения Microsoft Graph Application

Добавляет:

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

RSC vs Graph API

ВозможностьRSC-разрешенияGraph API
Сообщения в реальном времениДа (через webhook)Нет (только polling)
Историческые сообщенияНетДа (можно запрашивать историю)
Сложность настройкиТолько манифест приложенияТребуется admin consent + token flow
Работает офлайнНет (должен работать)Да (запрос в любое время)

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

Graph-медиа + история (обязательно для каналов)

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

  1. В Entra ID (Azure AD) App Registration добавьте Application разрешения Microsoft Graph:
    • ChannelMessage.Read.All (вложения каналов + история)
    • Chat.Read.All или ChatMessage.Read.All (групповые чаты)
  2. Выдайте admin consent для тенанта.
  3. Увеличьте версию манифеста Teams-приложения, загрузите заново и переустановите приложение в Teams.
  4. Полностью закройте и перезапустите Teams для очистки кэшированных метаданных.

Дополнительное разрешение для упоминания пользователей: @-упоминания пользователей работают из коробки для участников беседы. Однако для динамического поиска и упоминания пользователей, не участвующих в текущей беседе, добавьте разрешение User.Read.All (Application) и выдайте admin consent.

Известные ограничения

Таймауты webhook

Teams доставляет сообщения через HTTP webhook. Если обработка занимает слишком много времени (напр. медленные ответы 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: allowlist ЛС (рекомендуются AAD object ID). Мастер настройки разрешает имена в ID при наличии Graph-доступа.
  • channels.msteams.dangerouslyAllowNameMatching: аварийный режим для повторного включения сопоставления по изменяемым UPN/отображаемым именам и прямой маршрутизации по именам команд/каналов.
  • channels.msteams.textChunkLimit: размер чанка исходящего текста.
  • channels.msteams.chunkMode: length (по умолчанию) или newline для разделения по пустым строкам (границы абзацев) перед разделением по длине.
  • channels.msteams.mediaAllowHosts: allowlist хостов для входящих вложений (по умолчанию — домены Microsoft/Teams).
  • channels.msteams.mediaAuthAllowHosts: allowlist хостов для добавления заголовка Authorization при повторных попытках медиа (по умолчанию — хосты Graph + Bot Framework).
  • channels.msteams.requireMention: требовать @упоминание в каналах/группах (по умолчанию true).
  • channels.msteams.replyStyle: thread | top-level (см. Стиль ответов).
  • 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>).
    • Сообщения каналов/групп используют conversation id:
      • agent:<agentId>:msteams:channel:<conversationId>
      • agent:<agentId>:msteams:group:<conversationId>

Стиль ответов: треды vs посты

Teams недавно представил два стиля UI каналов поверх одной модели данных:

СтильОписаниеРекомендуемый replyStyle
Posts (классический)Сообщения отображаются карточками с ответами под нимиthread (по умолчанию)
Threads (в стиле Slack)Сообщения идут линейным потоком, как в Slacktop-level

Проблема: API Teams не раскрывает, какой стиль UI использует канал. При неправильном replyStyle:

  • thread в канале Threads-стиля → ответы вкладываются неуклюже
  • top-level в канале Posts-стиля → ответы появляются как отдельные посты верхнего уровня вместо тредов

Решение: Настройте replyStyle для каждого канала в зависимости от его UI:

{
  "msteams": {
    "replyStyle": "thread",
    "teams": {
      "19:[email protected]": {
        "channels": {
          "19:[email protected]": {
            "replyStyle": "top-level"
          }
        }
      }
    }
  }
}

Вложения и изображения

Текущие ограничения:

  • ЛС: изображения и файловые вложения работают через Teams bot file API.
  • Каналы/группы: вложения хранятся в M365 (SharePoint/OneDrive). Полезная нагрузка webhook содержит только HTML-заглушку, а не байты файла. Для загрузки вложений из каналов необходимы разрешения Graph API.

Без разрешений Graph сообщения канала с изображениями принимаются только как текст (содержимое изображения недоступно боту). По умолчанию OpenClaw загружает медиа только с хостов Microsoft/Teams. Переопределяйте через channels.msteams.mediaAllowHosts (используйте ["*"] для разрешения любого хоста). Заголовки Authorization добавляются только для хостов из channels.msteams.mediaAuthAllowHosts (по умолчанию — хосты Graph + Bot Framework). Держите этот список строгим (избегайте мультитенантных суффиксов).

Отправка файлов в групповых чатах

Боты могут отправлять файлы в ЛС через процесс FileConsentCard (встроенный). Однако отправка файлов в групповых чатах/каналах требует дополнительной настройки:

КонтекстСпособ отправкиНеобходимая настройка
ЛСFileConsentCard → пользователь принимает → бот загружаетРаботает из коробки
Групповые чаты/каналыЗагрузка в SharePoint → ссылка для общего доступаТребуется sharePointSiteId + разрешения Graph
Изображения (любой контекст)Base64-кодирование inlineРаботает из коробки

Почему групповые чаты требуют SharePoint

У ботов нет персонального OneDrive (эндпоинт Graph API /me/drive не работает для application identity). Для отправки файлов в групповых чатах/каналах бот загружает файлы на сайт SharePoint и создаёт ссылку для общего доступа.

Настройка

  1. Добавьте разрешения Graph API в Entra ID (Azure AD) → App Registration:

    • Sites.ReadWrite.All (Application) — загрузка файлов в SharePoint
    • Chat.Read.All (Application) — опционально, позволяет создавать ссылки для конкретных пользователей
  2. Выдайте admin consent для тенанта.

  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:/sites/BotFiles"
    
    # В ответе: "id": "contoso.sharepoint.com,guid1,guid2"
  4. Настройте OpenClaw:

    {
      channels: {
        msteams: {
          // ... остальная конфигурация ...
          sharePointSiteId: "contoso.sharepoint.com,guid1,guid2",
        },
      },
    }

Поведение общего доступа

РазрешениеПоведение
Только Sites.ReadWrite.AllСсылка для всей организации (доступна всем в организации)
Sites.ReadWrite.All + Chat.Read.AllСсылка для конкретных пользователей (доступна только участникам чата)

Ссылки для конкретных пользователей безопаснее, так как файл доступен только участникам чата. При отсутствии разрешения Chat.Read.All бот откатывается к ссылкам для всей организации.

Резервное поведение

СценарийРезультат
Групповой чат + файл + sharePointSiteId настроенЗагрузка в SharePoint, отправка ссылки
Групповой чат + файл + нет sharePointSiteIdПопытка загрузки в OneDrive (может не сработать), только текст
Персональный чат + файлFileConsentCard (работает без SharePoint)
Любой контекст + изображениеBase64-кодирование inline (работает без SharePoint)

Место хранения файлов

Загруженные файлы хранятся в папке /OpenClawShared/ в библиотеке документов по умолчанию настроенного сайта SharePoint.

Опросы (Adaptive Cards)

OpenClaw отправляет опросы Teams через Adaptive Cards (нативного API опросов в Teams нет).

  • CLI: openclaw message poll --channel msteams --target conversation:<id> ...
  • Голоса записываются шлюзом в ~/.openclaw/msteams-polls.json.
  • Шлюз должен оставаться онлайн для записи голосов.
  • Опросы пока не отправляют автоматические сводки результатов (при необходимости проверяйте файл хранилища).

Adaptive Cards (произвольные)

Отправляйте любой JSON Adaptive Card пользователям или беседам Teams через инструмент message или CLI.

Параметр card принимает объект JSON Adaptive Card. При указании card текст сообщения опционален.

Инструмент агента:

{
  "action": "send",
  "channel": "msteams",
  "target": "user:<id>",
  "card": {
    "type": "AdaptiveCard",
    "version": "1.5",
    "body": [{ "type": "TextBlock", "text": "Hello!" }]
  }
}

CLI:

openclaw message send --channel msteams \
  --target "conversation:19:[email protected]" \
  --card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello!"}]}'

См. документацию Adaptive Cards для схемы и примеров. Подробности формата адресатов см. в разделе Форматы адресатов ниже.

Форматы адресатов

В MSTeams для различения пользователей и бесед используются префиксы:

Тип адресатаФорматПример
Пользователь (по ID)user:<aad-object-id>user:40a1a0ed-4ff2-4164-a219-55518990c197
Пользователь (по имени)user:<display-name>user:John Smith (требуется Graph API)
Группа/каналconversation:<conversation-id>conversation:19:[email protected]
Группа/канал (raw)<conversation-id>19:[email protected] (если содержит @thread)

Примеры CLI:

# Отправка пользователю по ID
openclaw message send --channel msteams --target "user:40a1a0ed-..." --message "Hello"

# Отправка пользователю по отображаемому имени (вызывает Graph API)
openclaw message send --channel msteams --target "user:John Smith" --message "Hello"

# Отправка в групповой чат или канал
openclaw message send --channel msteams --target "conversation:19:[email protected]" --message "Hello"

# Отправка Adaptive Card в беседу
openclaw message send --channel msteams --target "conversation:19:[email protected]" \
  --card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello"}]}'

Примеры инструмента агента:

{
  "action": "send",
  "channel": "msteams",
  "target": "user:John Smith",
  "message": "Hello!"
}
{
  "action": "send",
  "channel": "msteams",
  "target": "conversation:19:[email protected]",
  "card": {
    "type": "AdaptiveCard",
    "version": "1.5",
    "body": [{ "type": "TextBlock", "text": "Hello" }]
  }
}

Примечание: Без префикса user: имена по умолчанию разрешаются как группа/команда. Всегда используйте user: при адресации людей по отображаемому имени.

Проактивные сообщения

  • Проактивные сообщения возможны только после взаимодействия пользователя, так как ссылки на беседы сохраняются в этот момент.
  • См. /gateway/configuration для dmPolicy и allowlist-ограничений.

ID команд и каналов (распространённая ошибка)

Параметр groupId в URL Teams — это НЕ ID команды для конфигурации. Извлекайте ID из пути URL:

URL команды:

https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
                                    └────────────────────────────┘
                                    Team ID (URL-декодируйте это)

URL канала:

https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
                                      └─────────────────────────┘
                                      Channel ID (URL-декодируйте это)

Для конфигурации:

  • Team ID = сегмент пути после /team/ (URL-декодированный, напр. 19:[email protected])
  • Channel ID = сегмент пути после /channel/ (URL-декодированный)
  • Игнорируйте параметр запроса groupId

Приватные каналы

У ботов ограниченная поддержка в приватных каналах:

ФункцияСтандартные каналыПриватные каналы
Установка ботаДаОграничено
Сообщения в реальном времени (webhook)ДаМожет не работать
RSC-разрешенияДаМогут работать иначе
@-упоминанияДаЕсли бот доступен
История через Graph APIДаДа (с разрешениями)

Обходные пути при проблемах с приватными каналами:

  1. Используйте стандартные каналы для взаимодействия с ботом
  2. Используйте ЛС — пользователи всегда могут писать боту напрямую
  3. Используйте Graph API для исторического доступа (требуется ChannelMessage.Read.All)

Устранение неполадок

Распространённые проблемы

  • Изображения не отображаются в каналах: отсутствуют разрешения Graph или admin consent. Переустановите Teams-приложение и полностью перезапустите Teams.
  • Нет ответов в канале: по умолчанию требуется упоминание; установите channels.msteams.requireMention=false или настройте для команды/канала.
  • Несоответствие версий (Teams показывает старый манифест): удалите и заново добавьте приложение, полностью перезапустите Teams для обновления.
  • 401 Unauthorized от webhook: ожидаемо при ручном тестировании без Azure JWT — означает, что эндпоинт достижим, но авторизация не прошла. Для корректного теста используйте Azure Web Chat.

Ошибки загрузки манифеста

  • «Icon file cannot be empty»: манифест ссылается на файлы иконок размером 0 байт. Создайте валидные PNG (32x32 для outline.png, 192x192 для color.png).
  • «webApplicationInfo.Id already in use»: приложение всё ещё установлено в другой команде/чате. Сначала найдите и удалите его, или подождите 5-10 минут.
  • «Something went wrong» при загрузке: загрузите через https://admin.teams.microsoft.com, откройте DevTools (F12) → вкладку Network и проверьте тело ответа для реальной ошибки.
  • Ошибка sideload: попробуйте «Upload an app to your org’s app catalog» вместо «Upload a custom app» — это часто обходит ограничения sideload.

RSC-разрешения не работают

  1. Убедитесь, что webApplicationInfo.id точно совпадает с App ID бота
  2. Загрузите приложение заново и переустановите в команде/чате
  3. Проверьте, не заблокировал ли администратор организации RSC-разрешения
  4. Убедитесь в использовании правильной области: ChannelMessage.Read.Group для команд, ChatMessage.Read.Chat для групповых чатов

Ссылки