Mainstream messaging
Microsoft Teams
Стан: підтримуються текст і вкладення в DM; надсилання файлів у каналах/групах потребує sharePointSiteId + дозволів Graph (див. Надсилання файлів у групових чатах). Опитування надсилаються через Adaptive Cards. Дії повідомлень надають явну дію upload-file для надсилань, де файл іде першим.
Вбудований plugin
Microsoft Teams постачається як вбудований plugin у поточних випусках OpenClaw, тому в звичайній пакетованій збірці окреме встановлення не потрібне.
Якщо ви використовуєте старішу збірку або кастомне встановлення, яке виключає вбудований Teams, установіть npm-пакет напряму:
openclaw plugins install @openclaw/msteamsВикористовуйте пакет без версії, щоб відстежувати поточний офіційний тег випуску. Закріплюйте точну версію лише тоді, коли вам потрібне відтворюване встановлення.
Локальний checkout (під час запуску з git-репозиторію):
openclaw plugins install ./path/to/local/msteams-pluginДокладно: Plugins
Швидке налаштування
@microsoft/teams.cli виконує реєстрацію бота, створення маніфесту та генерацію облікових даних однією командою.
1. Установіть і ввійдіть
npm install -g @microsoft/teams.cli@previewteams loginteams status # verify you're logged in and see your tenant info2. Запустіть тунель (Teams не може звертатися до localhost)
Установіть і автентифікуйте devtunnel CLI, якщо ще цього не зробили (посібник із початку роботи).
# One-time setup (persistent URL across sessions):devtunnel create my-openclaw-bot --allow-anonymousdevtunnel port create my-openclaw-bot -p 3978 --protocol auto # Each dev session:devtunnel host my-openclaw-bot# Your endpoint: https://<tunnel-id>.devtunnels.ms/api/messagesАльтернативи: ngrok http 3978 або tailscale funnel 3978 (але вони можуть змінювати URL у кожному сеансі).
3. Створіть застосунок
teams app create \ --name "OpenClaw" \ --endpoint "https://<your-tunnel-url>/api/messages"Ця одна команда:
- Створює застосунок Entra ID (Azure AD)
- Генерує клієнтський секрет
- Збирає та завантажує маніфест застосунку Teams (з іконками)
- Реєструє бота (за замовчуванням керований Teams - передплата Azure не потрібна)
Вивід покаже CLIENT_ID, CLIENT_SECRET, TENANT_ID і Teams App ID - занотуйте їх для наступних кроків. Він також пропонує встановити застосунок у Teams напряму.
4. Налаштуйте OpenClaw за допомогою облікових даних із виводу:
{ channels: { msteams: { enabled: true, appId: "<CLIENT_ID>", appPassword: "<CLIENT_SECRET>", tenantId: "<TENANT_ID>", webhook: { port: 3978, path: "/api/messages" }, }, },}Або використовуйте змінні середовища напряму: MSTEAMS_APP_ID, MSTEAMS_APP_PASSWORD, MSTEAMS_TENANT_ID.
5. Установіть застосунок у Teams
teams app create запропонує встановити застосунок - виберіть "Install in Teams". Якщо ви пропустили цей крок, посилання можна отримати пізніше:
teams app get <teamsAppId> --install-link6. Перевірте, що все працює
teams app doctor <teamsAppId>Це запускає діагностику реєстрації бота, конфігурації застосунку AAD, чинності маніфесту та налаштування SSO.
Для production-розгортань розгляньте використання федеративної автентифікації (сертифікат або керована ідентичність) замість клієнтських секретів.
Цілі
- Спілкуйтеся з OpenClaw через DM, групові чати або канали Teams.
- Зберігайте детерміновану маршрутизацію: відповіді завжди повертаються в канал, з якого вони надійшли.
- За замовчуванням використовуйте безпечну поведінку каналу (згадки обов’язкові, якщо не налаштовано інакше).
Записи конфігурації
За замовчуванням Microsoft Teams дозволено записувати оновлення конфігурації, спричинені /config set|unset (потребує commands.config: true).
Вимкніть за допомогою:
{ channels: { msteams: { configWrites: false } },}Контроль доступу (DM + групи)
Доступ до DM
- За замовчуванням:
channels.msteams.dmPolicy = "pairing". Невідомі відправники ігноруються, доки їх не буде схвалено. channels.msteams.allowFromмає використовувати стабільні object ID AAD або статичні групи доступу відправників, як-отaccessGroup:core-team.- Не покладайтеся на зіставлення UPN/display-name для allowlist - вони можуть змінюватися. OpenClaw вимикає пряме зіставлення імен за замовчуванням; увімкніть його явно через
channels.msteams.dangerouslyAllowNameMatching: true. - Майстер може зіставляти імена з ID через Microsoft Graph, коли облікові дані це дозволяють.
Доступ до груп
- За замовчуванням:
channels.msteams.groupPolicy = "allowlist"(заблоковано, якщо ви не додалиgroupAllowFrom). Використовуйтеchannels.defaults.groupPolicy, щоб перевизначити стандартне значення, коли воно не задане. channels.msteams.groupAllowFromкерує тим, які відправники або статичні групи доступу відправників можуть запускати дії в групових чатах/каналах (із fallback доchannels.msteams.allowFrom).- Задайте
groupPolicy: "open", щоб дозволити будь-якого учасника (за замовчуванням усе ще з перевіркою згадки). - Щоб не дозволяти жодних каналів, задайте
channels.msteams.groupPolicy: "disabled".
Приклад:
{ channels: { msteams: { groupPolicy: "allowlist", groupAllowFrom: ["00000000-0000-0000-0000-000000000000", "accessGroup:core-team"], }, },}Teams + allowlist каналів
- Обмежуйте відповіді груп/каналів, перелічуючи teams і канали в
channels.msteams.teams. - Ключі мають використовувати стабільні conversation ID Teams із посилань Teams, а не змінні display names.
- Коли
groupPolicy="allowlist"і наявний allowlist teams, приймаються лише перелічені teams/канали (з перевіркою згадки). - Майстер налаштування приймає записи
Team/Channelі зберігає їх для вас. - Під час запуску OpenClaw зіставляє імена team/channel і користувацького allowlist з ID (коли дозволи Graph це дозволяють)
і журналює мапінг; нерозпізнані імена team/channel зберігаються так, як введено, але за замовчуванням ігноруються для маршрутизації, якщо не ввімкнено
channels.msteams.dangerouslyAllowNameMatching: true.
Приклад:
{ channels: { msteams: { groupPolicy: "allowlist", teams: { "My Team": { channels: { General: { requireMention: true }, }, }, }, }, },}Ручне налаштування (без Teams CLI)
Якщо ви не можете використовувати Teams CLI, можна налаштувати бота вручну через Azure Portal.
Як це працює
- Переконайтеся, що plugin Microsoft Teams доступний (вбудований у поточні випуски).
- Створіть Azure Bot (App ID + секрет + tenant ID).
- Зберіть пакет застосунку Teams, який посилається на бота й містить наведені нижче дозволи RSC.
- Завантажте/установіть застосунок Teams у team (або personal scope для DM).
- Налаштуйте
msteamsу~/.openclaw/openclaw.json(або env vars) і запустіть gateway. - Gateway за замовчуванням слухає трафік Webhook Bot Framework на
/api/messages.
Крок 1: Створіть Azure Bot
-
Перейдіть до Create Azure Bot
-
Заповніть вкладку Basics:
Поле Значення Bot handle Ім’я вашого бота, напр., openclaw-msteams(має бути унікальним)Subscription Виберіть свою передплату Azure Resource group Створіть нову або використайте наявну Pricing tier Free для dev/testing Type of App Single Tenant (рекомендовано - див. примітку нижче) Creation type Create new Microsoft App ID
- Натисніть Review + create → Create (зачекайте ~1-2 хвилини)
Крок 2: Отримайте облікові дані
- Перейдіть до ресурсу Azure Bot → Configuration
- Скопіюйте Microsoft App ID → це ваш
appId - Натисніть Manage Password → перейдіть до App Registration
- У Certificates & secrets → New client secret → скопіюйте Value → це ваш
appPassword - Перейдіть до Overview → скопіюйте Directory (tenant) ID → це ваш
tenantId
Крок 3: Налаштуйте Messaging Endpoint
- В Azure Bot → Configuration
- Задайте Messaging endpoint як URL вашого Webhook:
- Production:
https://your-domain.com/api/messages - Local dev: використайте тунель (див. Локальна розробка нижче)
- Production:
Крок 4: Увімкніть канал Teams
- В Azure Bot → Channels
- Натисніть Microsoft Teams → Configure → Save
- Прийміть Terms of Service
Крок 5: Зберіть маніфест застосунку Teams
- Додайте запис
botзbotId = <App ID>. - Scopes:
personal,team,groupChat. supportsFiles: true(потрібно для обробки файлів у personal scope).- Додайте дозволи RSC (див. Дозволи RSC).
- Створіть іконки:
outline.png(32x32) іcolor.png(192x192). - Заархівуйте всі три файли разом:
manifest.json,outline.png,color.png.
Крок 6: Налаштуйте OpenClaw
{ channels: { 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.
Крок 7: Запустіть Gateway
Канал Teams запускається автоматично, коли plugin доступний і існує конфігурація msteams з обліковими даними.
Федеративна автентифікація (сертифікат плюс керована ідентичність)
Додано в 2026.4.11
Для production-розгортань OpenClaw підтримує федеративну автентифікацію як безпечнішу альтернативу клієнтським секретам. Доступні два методи:
Варіант A: автентифікація на основі сертифіката
Використовуйте PEM-сертифікат, зареєстрований у реєстрації застосунку Entra ID.
Налаштування:
- Згенеруйте або отримайте сертифікат (формат PEM із приватним ключем).
- В Entra ID → App Registration → Certificates & secrets → Certificates → завантажте публічний сертифікат.
Конфігурація:
{ channels: { msteams: { enabled: true, appId: "<APP_ID>", tenantId: "<TENANT_ID>", authType: "federated", certificatePath: "/path/to/cert.pem", webhook: { port: 3978, path: "/api/messages" }, }, },}Env vars:
MSTEAMS_AUTH_TYPE=federatedMSTEAMS_CERTIFICATE_PATH=/path/to/cert.pem
Варіант B: Azure Managed Identity
Використовуйте Azure Managed Identity для автентифікації без пароля. Це ідеально для розгортань в інфраструктурі Azure (AKS, App Service, Azure VMs), де доступна керована ідентичність.
Як це працює:
- Pod/VM бота має керовану ідентичність (system-assigned або user-assigned).
- Облікові дані федеративної ідентичності пов’язують керовану ідентичність із реєстрацією застосунку Entra ID.
- Під час виконання OpenClaw використовує
@azure/identity, щоб отримати токени з Azure IMDS endpoint (169.254.169.254). - Токен передається в Teams SDK для автентифікації бота.
Передумови:
- Інфраструктура Azure з увімкненою керованою ідентичністю (AKS workload identity, App Service, VM)
- Облікові дані федеративної ідентичності, створені в реєстрації застосунку Entra ID
- Мережевий доступ до IMDS (
169.254.169.254:80) з pod/VM
Конфігурація (system-assigned managed identity):
{ channels: { msteams: { enabled: true, appId: "<APP_ID>", tenantId: "<TENANT_ID>", authType: "federated", useManagedIdentity: true, webhook: { port: 3978, path: "/api/messages" }, }, },}Конфігурація (керована ідентичність, призначена користувачем):
{ channels: { msteams: { enabled: true, appId: "<APP_ID>", tenantId: "<TENANT_ID>", authType: "federated", useManagedIdentity: true, managedIdentityClientId: "<MI_CLIENT_ID>", webhook: { port: 3978, path: "/api/messages" }, }, },}Змінні середовища:
MSTEAMS_AUTH_TYPE=federatedMSTEAMS_USE_MANAGED_IDENTITY=trueMSTEAMS_MANAGED_IDENTITY_CLIENT_ID=<client-id>(лише для призначеної користувачем)
Налаштування AKS Workload Identity
Для розгортань AKS, що використовують workload identity:
-
Увімкніть workload identity у своєму кластері AKS.
-
Створіть облікові дані федеративної ідентичності у реєстрації застосунку Entra ID:
bash az ad app federated-credential create --id <APP_OBJECT_ID> --parameters '{ "name": "my-bot-workload-identity", "issuer": "<AKS_OIDC_ISSUER_URL>", "subject": "system:serviceaccount:<NAMESPACE>:<SERVICE_ACCOUNT>", "audiences": ["api://AzureADTokenExchange"]}' -
Додайте анотацію до сервісного облікового запису Kubernetes з ID клієнта застосунку:
yaml apiVersion: v1kind: ServiceAccountmetadata: name: my-bot-sa annotations: azure.workload.identity/client-id: "<APP_CLIENT_ID>" -
Додайте мітку до pod для ін’єкції workload identity:
yaml metadata: labels: azure.workload.identity/use: "true" -
Переконайтеся в наявності мережевого доступу до IMDS (
169.254.169.254) - якщо використовується NetworkPolicy, додайте правило egress, яке дозволяє трафік до169.254.169.254/32на порту 80.
Порівняння типів автентифікації
| Метод | Конфігурація | Переваги | Недоліки |
|---|---|---|---|
| Секрет клієнта | appPassword |
Просте налаштування | Потрібна ротація секретів, менш безпечно |
| Сертифікат | authType: "federated" + certificatePath |
Немає спільного секрету через мережу | Додаткове керування сертифікатами |
| Managed Identity | authType: "federated" + useManagedIdentity |
Без пароля, немає секретів для керування | Потрібна інфраструктура Azure |
Типова поведінка: Коли authType не задано, OpenClaw типово використовує автентифікацію за секретом клієнта. Наявні конфігурації продовжують працювати без змін.
Локальна розробка (тунелювання)
Teams не може звертатися до localhost. Використовуйте постійний dev-тунель, щоб ваша URL-адреса залишалася однаковою між сесіями:
# One-time setup:devtunnel create my-openclaw-bot --allow-anonymousdevtunnel port create my-openclaw-bot -p 3978 --protocol auto # Each dev session:devtunnel host my-openclaw-botАльтернативи: ngrok http 3978 або tailscale funnel 3978 (URL-адреси можуть змінюватися в кожній сесії).
Якщо URL-адреса тунелю змінюється, оновіть endpoint:
teams app update <teamsAppId> --endpoint "https://<new-url>/api/messages"Тестування бота
Запустіть діагностику:
teams app doctor <teamsAppId>Перевіряє реєстрацію бота, застосунок AAD, маніфест і конфігурацію SSO за один прохід.
Надішліть тестове повідомлення:
- Установіть застосунок Teams (скористайтеся посиланням для встановлення з
teams app get <id> --install-link) - Знайдіть бота в Teams і надішліть DM
- Перевірте журнали Gateway на вхідну активність
Змінні середовища
Натомість усі ключі конфігурації можна задати через змінні середовища:
MSTEAMS_APP_IDMSTEAMS_APP_PASSWORDMSTEAMS_TENANT_IDMSTEAMS_AUTH_TYPE(необов’язково:"secret"або"federated")MSTEAMS_CERTIFICATE_PATH(federated + certificate)MSTEAMS_CERTIFICATE_THUMBPRINT(необов’язково, не потрібно для автентифікації)MSTEAMS_USE_MANAGED_IDENTITY(federated + managed identity)MSTEAMS_MANAGED_IDENTITY_CLIENT_ID(лише MI, призначена користувачем)
Дія інформації про учасника
OpenClaw надає дію member-info на основі Graph для Microsoft Teams, щоб агенти й автоматизації могли отримувати деталі учасників каналу (відображуване ім’я, електронну пошту, роль) безпосередньо з Microsoft Graph.
Вимоги:
- Дозвіл RSC
Member.Read.Group(уже є в рекомендованому маніфесті) - Для пошуків між командами: дозвіл Graph Application
User.Read.Allзі згодою адміністратора
Дія керується channels.msteams.actions.memberInfo (типово: увімкнено, коли доступні облікові дані Graph).
Контекст історії
channels.msteams.historyLimitкерує тим, скільки останніх повідомлень каналу/групи загортається в prompt.- Повертається до
messages.groupChat.historyLimit. Установіть0, щоб вимкнути (типово 50). - Отримана історія thread фільтрується за allowlist відправників (
allowFrom/groupAllowFrom), тому початкове наповнення контексту thread включає лише повідомлення від дозволених відправників. - Контекст цитованих вкладень (
ReplyTo*, отриманий із HTML-відповіді Teams) наразі передається як отримано. - Іншими словами, allowlist визначають, хто може запускати агента; сьогодні фільтруються лише окремі додаткові шляхи контексту.
- Історію DM можна обмежити за допомогою
channels.msteams.dmHistoryLimit(ходи користувача). Перевизначення для окремих користувачів:channels.msteams.dms["<user_id>"].historyLimit.
Поточні дозволи Teams RSC (маніфест)
Це наявні resourceSpecific permissions у нашому маніфесті застосунку Teams. Вони застосовуються лише всередині команди/чату, де встановлено застосунок.
Для каналів (область команди):
ChannelMessage.Read.Group(Application) - отримувати всі повідомлення каналу без @mentionChannelMessage.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) - отримувати всі повідомлення групового чату без @mention
Щоб додати дозволи RSC через Teams CLI:
teams app rsc add <teamsAppId> ChannelMessage.Read.Group --type 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має містити читання/надсилання каналу, якщо вам потрібен трафік каналу.
Оновлення наявного застосунку
Щоб оновити вже встановлений застосунок Teams (наприклад, додати дозволи RSC):
# Download, edit, and re-upload the manifestteams app manifest download <teamsAppId> manifest.json# Edit manifest.json locally...teams app manifest upload manifest.json <teamsAppId># Version is auto-bumped if content changedПісля оновлення перевстановіть застосунок у кожній команді, щоб нові дозволи набули чинності, і повністю закрийте та перезапустіть Teams (не просто закрийте вікно), щоб очистити кешовані метадані застосунку.
Ручне оновлення маніфесту (без CLI)
- Оновіть свій
manifest.jsonновими налаштуваннями - Збільште поле
version(наприклад,1.0.0→1.1.0) - Повторно заархівуйте маніфест з іконками (
manifest.json,outline.png,color.png) - Завантажте новий zip:
- Teams Admin Center: Teams apps → Manage apps → знайдіть свій застосунок → Upload new version
- Sideload: У Teams → Apps → Manage your apps → Upload a custom app
Можливості: лише RSC проти Graph
З лише Teams RSC (застосунок установлено, без дозволів Graph API)
Працює:
- Читання текстового вмісту повідомлень каналу.
- Надсилання текстового вмісту повідомлень каналу.
- Отримання файлових вкладень особистих (DM) повідомлень.
НЕ працює:
- Зображення або вміст файлів у каналі/групі (payload містить лише HTML-заглушку).
- Завантаження вкладень, збережених у SharePoint/OneDrive.
- Читання історії повідомлень (поза живою подією Webhook).
З Teams RSC + дозволами Microsoft Graph Application
Додає:
- Завантаження розміщеного вмісту (зображень, вставлених у повідомлення).
- Завантаження файлових вкладень, збережених у SharePoint/OneDrive.
- Читання історії повідомлень каналу/чату через Graph.
RSC проти Graph API
| Можливість | Дозволи RSC | Graph API |
|---|---|---|
| Повідомлення в реальному часі | Так (через Webhook) | Ні (лише опитування) |
| Історичні повідомлення | Ні | Так (можна запитувати історію) |
| Складність налаштування | Лише маніфест застосунку | Потрібна згода адміністратора + потік токена |
| Працює офлайн | Ні (має бути запущено) | Так (запит будь-коли) |
Підсумок: RSC призначений для прослуховування в реальному часі; Graph API - для історичного доступу. Щоб наздоганяти пропущені повідомлення під час офлайну, потрібен Graph API з ChannelMessage.Read.All (потребує згоди адміністратора).
Медіа + історія з Graph (потрібно для каналів)
Якщо вам потрібні зображення/файли в каналах або ви хочете отримувати історію повідомлень, потрібно ввімкнути дозволи Microsoft Graph і надати згоду адміністратора.
- У App Registration Entra ID (Azure AD) додайте Application permissions Microsoft Graph:
ChannelMessage.Read.All(вкладення каналу + історія)Chat.Read.AllабоChatMessage.Read.All(групові чати)
- Надайте згоду адміністратора для tenant.
- Збільште версію маніфесту застосунку Teams, завантажте його повторно та перевстановіть застосунок у Teams.
- Повністю закрийте та перезапустіть Teams, щоб очистити кешовані метадані застосунку.
Додатковий дозвіл для згадок користувачів: @mentions користувачів працюють із коробки для користувачів у розмові. Однак, якщо ви хочете динамічно шукати й згадувати користувачів, які не перебувають у поточній розмові, додайте дозвіл User.Read.All (Application) і надайте згоду адміністратора.
Відомі обмеження
Тайм-аути Webhook
Teams доставляє повідомлення через HTTP Webhook. Якщо обробка триває надто довго (наприклад, повільні відповіді LLM), ви можете побачити:
- Тайм-аути Gateway
- Teams повторно надсилає повідомлення (спричиняючи дублікати)
- Відкинуті відповіді
OpenClaw обробляє це, швидко повертаючи відповідь і проактивно надсилаючи репліки, але дуже повільні відповіді все одно можуть спричиняти проблеми.
Підтримка хмари Teams і URL сервісу
Цей шлях Teams на базі SDK проходить живу перевірку для публічної хмари Microsoft Teams.
Вхідні відповіді використовують контекст turn вхідного Teams SDK. Проактивні операції поза контекстом - надсилання, редагування, видалення, картки, опитування, повідомлення з consent для файлів і поставлені в чергу довготривалі відповіді - використовують збережений serviceUrl посилання на розмову. Публічна хмара за замовчуванням використовує середовище публічної хмари Teams SDK і дозволяє збережені посилання на публічному хості Teams Connector: https://smba.trafficmanager.net/.
Публічна хмара є стандартною. Для звичайних ботів у публічній хмарі не потрібно задавати channels.msteams.cloud або channels.msteams.serviceUrl.
Для непублічних хмар Teams задайте cloud і відповідну проактивну межу, коли Microsoft її опублікує:
channels.msteams.cloudвибирає хмарний пресет Teams SDK для автентифікації, перевірки JWT, сервісів токенів і області Graph.channels.msteams.serviceUrlвибирає межу кінцевої точки Bot Connector, яка використовується для перевірки збережених посилань на розмови перед проактивними надсиланнями, редагуваннями, видаленнями, картками, опитуваннями, повідомленнями з consent для файлів і поставленими в чергу довготривалими відповідями. Це обов'язково для хмар USGov і DoD SDK. Для China/21Vianet OpenClaw використовує пресет SDKChinaі приймає збережені/налаштовані URL сервісу лише на хостах каналів Azure China Bot Framework.
Microsoft публікує глобальні проактивні кінцеві точки Bot Connector у розділі Створення розмови документації Teams щодо проактивних повідомлень. Використовуйте serviceUrl вхідної активності, коли він доступний; якщо потрібна глобальна проактивна кінцева точка, використовуйте таблицю Microsoft.
| Середовище Teams | Конфігурація OpenClaw | Проактивний serviceUrl |
|---|---|---|
| Public | конфігурація cloud/serviceUrl не потрібна | https://smba.trafficmanager.net/teams |
| GCC | задайте serviceUrl; окремого хмарного пресета Teams SDK немає |
https://smba.infra.gcc.teams.microsoft.com/teams |
| GCC High | cloud: "USGov" + serviceUrl |
https://smba.infra.gov.teams.microsoft.us/teams |
| DoD | cloud: "USGovDoD" + serviceUrl |
https://smba.infra.dod.teams.microsoft.us/teams |
| China/21Vianet | cloud: "China" |
використовуйте serviceUrl вхідної активності |
Приклад для GCC, де Microsoft документує окремий проактивний URL сервісу, але Teams SDK не надає окремого хмарного пресета GCC:
{ "channels": { "msteams": { "serviceUrl": "https://smba.infra.gcc.teams.microsoft.com/teams" } }}Приклад для GCC High:
{ "channels": { "msteams": { "cloud": "USGov", "serviceUrl": "https://smba.infra.gov.teams.microsoft.us/teams" } }}channels.msteams.serviceUrl обмежено підтримуваними хостами Microsoft Teams Bot Connector. Коли URL сервісу налаштовано, OpenClaw перевіряє, що збережений serviceUrl розмови використовує той самий хост, перш ніж виконуються проактивні надсилання, редагування, видалення, картки, опитування або поставлені в чергу довготривалі відповіді. Із типовою конфігурацією публічної хмари OpenClaw fail-closed, якщо збережена розмова вказує за межі публічного хоста Teams Connector. Після зміни налаштувань хмари/URL сервісу отримайте нове повідомлення з розмови, щоб збережене посилання на розмову було актуальним.
China/21Vianet не має окремого глобального проактивного URL smba у таблиці проактивних кінцевих точок Teams від Microsoft. Налаштуйте cloud: "China", щоб Teams SDK використовував кінцеві точки автентифікації, токенів і JWT Azure China. Після цього проактивні надсилання потребують збереженого посилання на розмову з вхідної активності China Teams або явно налаштованого URL сервісу на межі каналу Azure China Bot Framework (*.botframework.azure.cn). Допоміжні функції Teams на базі Graph наразі вимкнено для cloud: "China", доки OpenClaw не маршрутизуватиме запити Graph через кінцеву точку Azure China Graph.
Форматування
Markdown у Teams обмеженіший, ніж у Slack або Discord:
- Базове форматування працює: жирний, курсив,
code, посилання - Складний markdown (таблиці, вкладені списки) може відображатися некоректно
- Adaptive Cards підтримуються для опитувань і семантичних презентаційних надсилань (див. нижче)
Конфігурація
Ключові налаштування (див. /gateway/configuration для спільних шаблонів каналів):
channels.msteams.enabled: увімкнути/вимкнути канал.channels.msteams.appId,channels.msteams.appPassword,channels.msteams.tenantId: облікові дані бота.channels.msteams.cloud: хмарне середовище Teams SDK (Public,USGov,USGovDoDабоChina; стандартноPublic). Задавайте це разом ізserviceUrlдля хмар USGov/DoD SDK; China використовує пресет SDK і збережені посилання на розмови Azure China Bot Framework, а допоміжні функції на базі Graph вимкнено, доки не буде реалізовано маршрутизацію Azure China Graph.channels.msteams.serviceUrl: межа URL сервісу Bot Connector для проактивних операцій SDK. Публічна хмара використовує стандартне значення SDK; задайте це для GCC (https://smba.infra.gcc.teams.microsoft.com/teams), GCC High або DoD. China приймає хости каналів Azure China Bot Framework, коли збережене посилання на розмову надходить із Teams, яким керує 21Vianet.channels.msteams.webhook.port(стандартно3978)channels.msteams.webhook.path(стандартно/api/messages)channels.msteams.dmPolicy:pairing | allowlist | open | disabled(стандартно: pairing)channels.msteams.allowFrom: allowlist DM (рекомендовано AAD object IDs). Майстер під час налаштування перетворює імена на IDs, коли доступний доступ до Graph.channels.msteams.dangerouslyAllowNameMatching: аварійний перемикач для повторного ввімкнення зіставлення змінних UPN/display-name і прямої маршрутизації за іменами team/channel.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: вимагати @mention у каналах/групах (стандартно 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мають використовувати явні префікси:channel:,id:,e164:,username:,name:(застарілі ключі без префікса все ще зіставляються лише зid:). channels.msteams.actions.memberInfo: увімкнути або вимкнути дію інформації про учасника на базі Graph (стандартно: увімкнено, коли доступні облікові дані Graph).channels.msteams.authType: тип автентифікації -"secret"(стандартно) або"federated".channels.msteams.certificatePath: шлях до файлу PEM-сертифіката (federated + certificate auth).channels.msteams.certificateThumbprint: відбиток сертифіката (необов'язково, не потрібно для auth).channels.msteams.useManagedIdentity: увімкнути автентифікацію керованої ідентичності (режим federated).channels.msteams.managedIdentityClientId: client ID для user-assigned managed identity.channels.msteams.sharePointSiteId: SharePoint site ID для завантажень файлів у групових чатах/каналах (див. Надсилання файлів у групових чатах).
Маршрутизація та сесії
- Ключі сесій відповідають стандартному формату агента (див. /concepts/session):
- Прямі повідомлення спільно використовують основну сесію (
agent:<agentId>:<mainKey>). - Повідомлення каналів/груп використовують ідентифікатор розмови:
agent:<agentId>:msteams:channel:<conversationId>agent:<agentId>:msteams:group:<conversationId>
- Прямі повідомлення спільно використовують основну сесію (
Стиль відповіді: гілки проти дописів
Teams нещодавно представив два стилі інтерфейсу каналів поверх тієї самої базової моделі даних:
| Стиль | Опис | Рекомендований replyStyle |
|---|---|---|
| Дописи (класичний) | Повідомлення відображаються як картки з ланцюжками відповідей під ними | thread (стандартно) |
| Гілки (подібний до Slack) | Повідомлення йдуть лінійно, більше схоже на Slack | top-level |
Проблема: Teams API не показує, який стиль інтерфейсу використовує канал. Якщо використати неправильний replyStyle:
threadу каналі зі стилем гілок → відповіді виглядають незручно вкладенимиtop-levelу каналі зі стилем дописів → відповіді з'являються як окремі дописи верхнього рівня замість відповідей у гілці
Рішення: Налаштуйте replyStyle для кожного каналу відповідно до того, як канал налаштовано:
{ channels: { msteams: { replyStyle: "thread", teams: { "19:abc...@thread.tacv2": { channels: { "19:xyz...@thread.tacv2": { replyStyle: "top-level", }, }, }, }, }, },}Пріоритет розв'язання
Коли бот надсилає відповідь у канал, replyStyle визначається від найконкретнішого перевизначення до стандартного значення. Перше значення, що не є undefined, перемагає:
- Для каналу —
channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle - Для команди —
channels.msteams.teams.<teamId>.replyStyle - Глобально —
channels.msteams.replyStyle - Неявне стандартне значення — виводиться з
requireMention:requireMention: true→threadrequireMention: false→top-level
Якщо встановити requireMention: false глобально без явного replyStyle, згадки в каналах зі стилем дописів відображатимуться як дописи верхнього рівня, навіть коли вхідне повідомлення було відповіддю в гілці. Закріпіть replyStyle: "thread" на глобальному рівні, рівні команди або каналу, щоб уникнути несподіванок.
Збереження контексту гілки
Коли діє replyStyle: "thread" і бота @mentioned зсередини гілки каналу, OpenClaw повторно прикріплює початковий корінь гілки до вихідного посилання на розмову (19:…@thread.tacv2;messageid=<root>), щоб відповідь потрапила в ту саму гілку. Це працює як для live (in-turn) надсилань, так і для проактивних надсилань після завершення строку дії turn-контексту Bot Framework (наприклад, довготривалі агенти, поставлені в чергу відповіді на tool-call через mcp__openclaw__message).
Корінь гілки береться зі збереженого threadId у посиланні на розмову. Старіші збережені посилання, що передують threadId, повертаються до activityId (будь-якої вхідної активності, яка востаннє ініціалізувала розмову), тому наявні розгортання продовжують працювати без повторного ініціалізування.
Коли діє replyStyle: "top-level", вхідні повідомлення потоків каналу навмисно отримують відповіді як нові дописи верхнього рівня — суфікс потоку не додається. Це правильна поведінка для каналів у стилі Threads; якщо ви бачите дописи верхнього рівня там, де очікували відповіді в потоці, ваш replyStyle налаштовано неправильно для цього каналу.
Вкладення та зображення
Поточні обмеження:
- DM: Зображення та файлові вкладення працюють через файлові API бота Teams.
- Канали/групи: Вкладення зберігаються в сховищі M365 (SharePoint/OneDrive). Корисне навантаження Webhook містить лише HTML-заглушку, а не фактичні байти файлу. Для завантаження вкладень каналу потрібні дозволи Graph API.
- Для явного надсилання спочатку файлу використовуйте
action=upload-fileзmedia/filePath/path; необов'язковеmessageстає супровідним текстом/коментарем, аfilenameперевизначає назву завантаженого файлу.
Без дозволів Graph повідомлення каналу із зображеннями надходитимуть лише як текст (вміст зображення недоступний боту).
За замовчуванням OpenClaw завантажує медіа лише з хостів Microsoft/Teams. Перевизначте це через channels.msteams.mediaAllowHosts (використовуйте ["*"], щоб дозволити будь-який хост).
Заголовки авторизації додаються лише для хостів у channels.msteams.mediaAuthAllowHosts (за замовчуванням це хости Graph + Bot Framework). Тримайте цей список суворим (уникайте суфіксів для кількох орендарів).
Надсилання файлів у групових чатах
Боти можуть надсилати файли в DM за допомогою потоку FileConsentCard (вбудовано). Однак надсилання файлів у групових чатах/каналах потребує додаткового налаштування:
| Контекст | Як надсилаються файли | Потрібне налаштування |
|---|---|---|
| DM | FileConsentCard → користувач приймає → бот завантажує | Працює з коробки |
| Групові чати/канали | Завантаження до SharePoint → посилання для спільного доступу | Потрібні sharePointSiteId + дозволи Graph |
| Зображення (будь-який контекст) | Вбудовано з кодуванням Base64 | Працює з коробки |
Чому груповим чатам потрібен SharePoint
Боти не мають особистого диска OneDrive (кінцева точка Graph API /me/drive не працює для ідентичностей застосунків). Щоб надсилати файли в групові чати/канали, бот завантажує їх на сайт SharePoint і створює посилання для спільного доступу.
Налаштування
-
Додайте дозволи Graph API в Entra ID (Azure AD) → App Registration:
Sites.ReadWrite.All(Application) - завантаження файлів до SharePointChat.Read.All(Application) - необов'язково, вмикає посилання для спільного доступу на рівні користувача
-
Надайте згоду адміністратора для орендаря.
-
Отримайте ID вашого сайту SharePoint:
bash # Via Graph Explorer or curl with a valid token:curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}" # Example: for a site at "contoso.sharepoint.com/sites/BotFiles"curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/BotFiles" # Response includes: "id": "contoso.sharepoint.com,guid1,guid2" -
Налаштуйте OpenClaw:
json5 { channels: { msteams: { // ... other config ... 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 (працює без SharePoint) |
Розташування збережених файлів
Завантажені файли зберігаються в папці /OpenClawShared/ у стандартній бібліотеці документів налаштованого сайту SharePoint.
Опитування (Adaptive Cards)
OpenClaw надсилає опитування Teams як Adaptive Cards (нативного API опитувань Teams немає).
- CLI:
openclaw message poll --channel msteams --target conversation:<id> ... - Голоси записуються Gateway у SQLite стану Plugin OpenClaw за адресою
state/openclaw.sqlite. - Наявні файли
msteams-polls.jsonімпортуються командоюopenclaw doctor --fix, а не запущеним Plugin. - Gateway має залишатися онлайн, щоб записувати голоси.
- Опитування ще не публікують автоматично підсумки результатів, і підтримуваного CLI для результатів опитувань ще немає.
Картки презентації
Надсилайте семантичні корисні навантаження презентації користувачам або розмовам Teams за допомогою інструмента message, CLI або звичайної доставки відповіді. OpenClaw відтворює їх як Teams Adaptive Cards із загального контракту презентації.
Параметр presentation приймає семантичні блоки. Коли надано presentation, текст повідомлення необов'язковий. Кнопки відтворюються як дії надсилання або URL в Adaptive Card. Меню вибору ще не є нативними в рендерері Teams, тому OpenClaw перед доставкою знижує їх до читабельного тексту.
Інструмент агента:
{ action: "send", channel: "msteams", target: "user:<id>", presentation: { title: "Hello", blocks: [{ type: "text", text: "Hello!" }], },}CLI:
openclaw message send --channel msteams \ --target "conversation:19:abc...@thread.tacv2" \ --presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello!"}]}'Докладніше про формат цілі див. у розділі Формати цілей нижче.
Формати цілей
Цілі 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:abc123...@thread.tacv2 |
| Група/канал (сирий) | <conversation-id> |
19:abc123...@thread.tacv2 (якщо містить @thread) |
Приклади CLI:
# Send to a user by IDopenclaw message send --channel msteams --target "user:40a1a0ed-..." --message "Hello" # Send to a user by display name (triggers Graph API lookup)openclaw message send --channel msteams --target "user:John Smith" --message "Hello" # Send to a group chat or channelopenclaw message send --channel msteams --target "conversation:19:abc...@thread.tacv2" --message "Hello" # Send a presentation card to a conversationopenclaw message send --channel msteams --target "conversation:19:abc...@thread.tacv2" \ --presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello"}]}'Приклади інструмента агента:
{ action: "send", channel: "msteams", target: "user:John Smith", message: "Hello!",}{ action: "send", channel: "msteams", target: "conversation:19:abc...@thread.tacv2", presentation: { title: "Hello", blocks: [{ type: "text", text: "Hello" }], },}Проактивні повідомлення
- Проактивні повідомлення можливі лише після взаємодії користувача, оскільки в цей момент ми зберігаємо посилання на розмову.
- Див.
/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 conversation ID (URL-decode this)URL каналу:
https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=... └─────────────────────────┘ Channel ID (URL-decode this)Для конфігурації:
- Ключ команди = сегмент шляху після
/team/(декодований з URL, наприклад19:Bk4j...@thread.tacv2; старіші орендарі можуть показувати@thread.skype, що також є дійсним) - Ключ каналу = сегмент шляху після
/channel/(декодований з URL) - Ігноруйте параметр запиту
groupIdдля маршрутизації OpenClaw. Це ID групи Microsoft Entra, а не ID розмови Bot Framework, який використовується у вхідних активностях Teams.
Приватні канали
Боти мають обмежену підтримку в приватних каналах:
| Функція | Стандартні канали | Приватні канали |
|---|---|---|
| Установлення бота | Так | Обмежено |
| Повідомлення в реальному часі (Webhook) | Так | Може не працювати |
| Дозволи RSC | Так | Можуть поводитися інакше |
| @mentions | Так | Якщо бот доступний |
| Історія Graph API | Так | Так (з дозволами) |
Обхідні шляхи, якщо приватні канали не працюють:
- Використовуйте стандартні канали для взаємодії з ботом
- Використовуйте DM - користувачі завжди можуть написати боту напряму
- Використовуйте Graph API для доступу до історії (потрібен
ChannelMessage.Read.All)
Усунення несправностей
Поширені проблеми
- Зображення не показуються в каналах: бракує дозволів Graph або згоди адміністратора. Перевстановіть застосунок 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 не працюють
- Перевірте, що
webApplicationInfo.idточно збігається з App ID вашого бота - Повторно завантажте застосунок і перевстановіть його в команді/чаті
- Перевірте, чи адміністратор вашої організації не заблокував дозволи RSC
- Переконайтеся, що використовуєте правильну область:
ChannelMessage.Read.Groupдля команд,ChatMessage.Read.Chatдля групових чатів
Посилання
- Створення Azure Bot - посібник із налаштування Azure Bot
- Портал розробника Teams - створення застосунків Teams і керування ними
- Схема маніфесту застосунку Teams
- Отримання повідомлень каналу за допомогою RSC
- Довідник дозволів RSC
- Обробка файлів ботом Teams (для каналу/групи потрібен Graph)
- Проактивні повідомлення
- @microsoft/teams.cli - Teams CLI для керування ботами
Пов’язане
- Огляд каналів - усі підтримувані канали
- Сполучення - автентифікація в DM і потік сполучення
- Групи - поведінка групових чатів і обмеження за згадками
- Маршрутизація каналів - маршрутизація сеансів для повідомлень
- Безпека - модель доступу й посилення захисту