Microsoft Teams (plugin)
“Abandon all hope, ye who enter here.”
Cập nhật: 2026-01-21
Trạng thái: Hỗ trợ tin nhắn văn bản + file đính kèm trong DM; gửi file trong channel/group cần sharePointSiteId + quyền Graph (xem Gửi file trong group chat). Poll được gửi qua Adaptive Cards.
Cần cài plugin
Microsoft Teams được cung cấp dưới dạng plugin và không đi kèm với bản cài đặt core.
Breaking change (2026.1.15): MS Teams đã được tách ra khỏi core. Nếu các bạn dùng nó, phải cài plugin.
Lý do: giữ cho bản cài core nhẹ hơn và cho phép các dependency của MS Teams cập nhật độc lập.
Cài đặt qua CLI (npm registry):
openclaw plugins install @openclaw/msteams
Local checkout (khi chạy từ git repo):
openclaw plugins install ./extensions/msteams
Nếu các bạn chọn Teams trong quá trình configure/onboarding và phát hiện git checkout, OpenClaw sẽ tự động đề xuất đường dẫn cài đặt local.
Chi tiết: Plugins
Cài đặt nhanh (cho người mới)
- Cài đặt plugin Microsoft Teams.
- Tạo một Azure Bot (App ID + client secret + tenant ID).
- Cấu hình OpenClaw với các credentials đó.
- Expose
/api/messages(mặc định port 3978) qua public URL hoặc tunnel. - Cài đặt Teams app package và khởi động gateway.
Config tối thiểu:
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
appPassword: "<APP_PASSWORD>",
tenantId: "<TENANT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Lưu ý: group chat bị chặn mặc định (channels.msteams.groupPolicy: "allowlist"). Để cho phép trả lời trong group, set channels.msteams.groupAllowFrom (hoặc dùng groupPolicy: "open" để cho phép bất kỳ thành viên nào, có mention-gated).
Mục tiêu
- Chat với OpenClaw qua Teams DM, group chat, hoặc channel.
- Giữ routing xác định: reply luôn quay về channel mà nó đến.
- Mặc định là hành vi channel an toàn (cần mention trừ khi cấu hình khác).
Ghi config
Mặc định, Microsoft Teams được phép ghi các cập nhật config được kích hoạt bởi /config set|unset (cần commands.config: true).
Tắt bằng:
{
channels: { msteams: { configWrites: false } },
}
Kiểm soát truy cập (DM + group)
Truy cập DM
- Mặc định:
channels.msteams.dmPolicy = "pairing". Người gửi không xác định sẽ bị bỏ qua cho đến khi được phê duyệt. channels.msteams.allowFromchấp nhận AAD object ID, UPN, hoặc display name. Wizard sẽ resolve name thành ID qua Microsoft Graph khi có credentials.
Truy cập Group
- Mặc định:
channels.msteams.groupPolicy = "allowlist"(bị chặn trừ khi các bạn thêmgroupAllowFrom). Dùngchannels.defaults.groupPolicyđể override mặc định khi chưa set. channels.msteams.groupAllowFromkiểm soát người gửi nào có thể trigger trong group chat/channel (fallback vềchannels.msteams.allowFrom).- Set
groupPolicy: "open"để cho phép bất kỳ thành viên nào (vẫn mention-gated mặc định). - Để không cho phép channel nào, set
channels.msteams.groupPolicy: "disabled".
Ví dụ:
{
channels: {
msteams: {
groupPolicy: "allowlist",
groupAllowFrom: ["[email protected]"],
},
},
}
Teams + channel allowlist
- Giới hạn group/channel reply bằng cách liệt kê team và channel trong
channels.msteams.teams. - Key có thể là team ID hoặc tên; channel key có thể là conversation ID hoặc tên.
- Khi
groupPolicy="allowlist"và có teams allowlist, chỉ các team/channel được liệt kê mới được chấp nhận (mention-gated). - Configure wizard chấp nhận entry
Team/Channelvà lưu trữ cho các bạn. - Khi khởi động, OpenClaw resolve team/channel và user allowlist name thành ID (khi có quyền Graph) và log mapping; các entry chưa resolve được giữ nguyên như đã nhập.
Ví dụ:
{
channels: {
msteams: {
groupPolicy: "allowlist",
teams: {
"My Team": {
channels: {
General: { requireMention: true },
},
},
},
},
},
}
Cách hoạt động
- Cài đặt plugin Microsoft Teams.
- Tạo một Azure Bot (App ID + secret + tenant ID).
- Build một Teams app package tham chiếu đến bot và bao gồm các quyền RSC bên dưới.
- Upload/cài đặt Teams app vào một team (hoặc personal scope cho DM).
- Cấu hình
msteamstrong~/.openclaw/openclaw.json(hoặc env vars) và khởi động gateway. - Gateway lắng nghe Bot Framework webhook traffic trên
/api/messagesmặc định.
Cài đặt Azure Bot (Yêu cầu trước)
Trước khi cấu hình OpenClaw, các bạn cần tạo một Azure Bot resource.
Bước 1: Tạo Azure Bot
-
Vào Create Azure Bot
-
Điền vào tab Basics:
Trường Giá trị Bot handle Tên bot của bạn, ví dụ openclaw-msteams(phải unique)Subscription Chọn Azure subscription của bạn Resource group Tạo mới hoặc dùng có sẵn Pricing tier Free cho dev/testing Type of App Single Tenant (khuyên dùng - xem lưu ý bên dưới) Creation type Create new Microsoft App ID
Lưu ý deprecation: Việc tạo multi-tenant bot mới đã bị deprecated sau 2025-07-31. Dùng Single Tenant cho bot mới nhé.
- Click Review + create → Create (đợi khoảng 1-2 phút)
Bước 2: Lấy Credentials
- Vào Azure Bot resource của bạn → Configuration
- Copy Microsoft App ID → đây là
appIdcủa bạn - Click Manage Password → vào App Registration
- Trong Certificates & secrets → New client secret → copy Value → đây là
appPasswordcủa bạn - Vào Overview → copy Directory (tenant) ID → đây là
tenantIdcủa bạn
Bước 3: Cấu hình Messaging Endpoint
- Trong Azure Bot → Configuration
- Set Messaging endpoint thành webhook URL của bạn:
- Production:
https://your-domain.com/api/messages - Local dev: Dùng tunnel (xem Local Development bên dưới)
- Production:
Bước 4: Bật Teams Channel
- Trong Azure Bot → Channels
- Click Microsoft Teams → Configure → Save
- Chấp nhận Terms of Service
Local Development (Tunneling)
Teams không thể kết nối tới localhost. Dùng tunnel cho local development:
Option A: ngrok
ngrok http 3978
# Copy URL https, ví dụ: https://abc123.ngrok.io
# Set messaging endpoint thành: https://abc123.ngrok.io/api/messages
Option B: Tailscale Funnel
tailscale funnel 3978
# Dùng Tailscale funnel URL của bạn làm messaging endpoint
Teams Developer Portal (Cách khác)
Thay vì tạo manifest ZIP thủ công, các bạn có thể dùng Teams Developer Portal:
- Click + New app
- Điền thông tin cơ bản (name, description, developer info)
- Vào App features → Bot
- Chọn Enter a bot ID manually và paste Azure Bot App ID của bạn
- Check scope: Personal, Team, Group Chat
- Click Distribute → Download app package
- Trong Teams: Apps → Manage your apps → Upload a custom app → chọn file ZIP
Cách này thường dễ hơn là chỉnh sửa JSON manifest thủ công.
Test Bot
Option A: Azure Web Chat (verify webhook trước)
- Trong Azure Portal → Azure Bot resource của bạn → Test in Web Chat
- Gửi một tin nhắn - bạn sẽ thấy response
- Điều này xác nhận webhook endpoint hoạt động trước khi setup Teams
Option B: Teams (sau khi cài app)
- Cài đặt Teams app (sideload hoặc org catalog)
- Tìm bot trong Teams và gửi DM
- Check gateway log để xem incoming activity
Cài đặt (chỉ text cơ bản)
-
Cài đặt plugin Microsoft Teams
- Từ npm:
openclaw plugins install @openclaw/msteams - Từ local checkout:
openclaw plugins install ./extensions/msteams
- Từ npm:
-
Đăng ký Bot
- Tạo Azure Bot (xem bên trên) và ghi lại:
- App ID
- Client secret (App password)
- Tenant ID (single-tenant)
- Tạo Azure Bot (xem bên trên) và ghi lại:
-
Teams app manifest
- Bao gồm entry
botvớibotId = <App ID>. - Scope:
personal,team,groupChat. supportsFiles: true(cần cho xử lý file trong personal scope).- Thêm quyền RSC (bên dưới).
- Tạo icon:
outline.png(32x32) vàcolor.png(192x192). - Zip cả ba file lại:
manifest.json,outline.png,color.png.
- Bao gồm entry
-
Cấu hình OpenClaw
{ "msteams": { "enabled": true, "appId": "<APP_ID>", "appPassword": "<APP_PASSWORD>", "tenantId": "<TENANT_ID>", "webhook": { "port": 3978, "path": "/api/messages" } } }Các bạn cũng có thể dùng biến môi trường thay vì config key:
MSTEAMS_APP_IDMSTEAMS_APP_PASSWORDMSTEAMS_TENANT_ID
-
Bot endpoint
- Set Azure Bot Messaging Endpoint thành:
https://<host>:3978/api/messages(hoặc path/port bạn chọn).
- Set Azure Bot Messaging Endpoint thành:
-
Chạy gateway
- Teams channel tự động khởi động khi plugin được cài và config
msteamstồn tại với credentials.
- Teams channel tự động khởi động khi plugin được cài và config
History context
channels.msteams.historyLimitkiểm soát số lượng tin nhắn channel/group gần đây được đưa vào prompt.- Fallback về
messages.groupChat.historyLimit. Set0để tắt (mặc định 50). - DM history có thể giới hạn bằng
channels.msteams.dmHistoryLimit(user turns). Override theo user:channels.msteams.dms["<user_id>"].historyLimit.
Quyền RSC hiện tại của Teams (Manifest)
Đây là các quyền resourceSpecific hiện có trong Teams app manifest của chúng ta. Chúng chỉ áp dụng bên trong team/chat nơi app được cài đặt.
Cho channel (team scope):
ChannelMessage.Read.Group(Application) - nhận tất cả tin nhắn channel mà không cần @mentionChannelMessage.Send.Group(Application)Member.Read.Group(Application)Owner.Read.Group(Application)ChannelSettings.Read.Group(Application)TeamMember.Read.Group(Application)TeamSettings.Read.Group(Application)
Cho group chat:
ChatMessage.Read.Chat(Application) - nhận tất cả tin nhắn group chat mà không cần @mention
Ví dụ Teams Manifest (đã ẩn thông tin)
Ví dụ tối thiểu, hợp lệ với các trường bắt buộc. Thay thế ID và 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" }
]
}
}
}
Lưu ý về Manifest (các trường bắt buộc)
bots[].botIdphải khớp với Azure Bot App ID.webApplicationInfo.idphải khớp với Azure Bot App ID.bots[].scopesphải bao gồm các surface bạn định dùng (personal,team,groupChat).bots[].supportsFiles: truecần cho xử lý file trong personal scope.authorization.permissions.resourceSpecificphải bao gồm channel read/send nếu bạn muốn channel traffic.
Cập nhật app đã tồn tại
Để cập nhật Teams app đã cài (ví dụ: thêm quyền RSC):
- Cập nhật
manifest.jsonvới các setting mới - Tăng trường
version(ví dụ:1.0.0→1.1.0) - Re-zip manifest với icon (
manifest.json,outline.png,color.png) - Upload zip mới:
- Option A (Teams Admin Center): Teams Admin Center → Teams apps → Manage apps → tìm app của bạn → Upload new version
- Option B (Sideload): Trong Teams → Apps → Manage your apps → Upload a custom app
- Cho team channel: Cài lại app trong mỗi team để quyền mới có hiệu lực
- Thoát hoàn toàn và khởi động lại Teams (không chỉ đóng cửa sổ) để xóa cached app metadata
Khả năng: Chỉ RSC vs Graph
Với chỉ Teams RSC (app đã cài, không có quyền Graph API)
Hoạt động:
- Đọc nội dung text tin nhắn channel.
- Gửi nội dung text tin nhắn channel.
- Nhận file đính kèm personal (DM).
KHÔNG hoạt động:
- Hình ảnh hoặc nội dung file trong channel/group (payload chỉ bao gồm HTML stub).
- Download attachment được lưu trong SharePoint/OneDrive.
- Đọc message history (ngoài live webhook event).
Với Teams RSC + quyền Microsoft Graph Application
Thêm:
- Download hosted content (hình ảnh paste vào tin nhắn).
- Download file attachment được lưu trong SharePoint/OneDrive.
- Đọc channel/chat message history qua Graph.
RSC vs Graph API
| Khả năng | Quyền RSC | Graph API |
|---|---|---|
| Tin nhắn real-time | Có (qua webhook) | Không (chỉ polling) |
| Tin nhắn lịch sử | Không | Có (có thể query history) |
| Độ phức tạp setup | Chỉ app manifest | Cần admin consent + token flow |
| Hoạt động offline | Không (phải đang chạy) | Có (query bất cứ lúc nào) |
Kết luận: RSC dùng cho lắng nghe real-time; Graph API dùng cho truy cập lịch sử. Để bắt kịp tin nhắn bị miss khi offline, các bạn cần Graph API với ChannelMessage.Read.All (cần admin consent).
Graph-enabled media + history (cần cho channel)
Nếu các bạn cần hình ảnh/file trong channel hoặc muốn fetch message history, phải bật quyền Microsoft Graph và grant admin consent.
- Trong Entra ID (Azure AD) App Registration, thêm Microsoft Graph Application permissions:
ChannelMessage.Read.All(channel attachment + history)Chat.Read.AllhoặcChatMessage.Read.All(group chat)
- Grant admin consent cho tenant.
- Tăng manifest version của Teams app, re-upload, và cài lại app trong Teams.
- Thoát hoàn toàn và khởi động lại Teams để xóa cached app metadata.
Hạn chế đã biết
Webhook timeout
Teams gửi tin nhắn qua HTTP webhook. Nếu xử lý quá lâu (ví dụ: LLM response chậm), các bạn có thể thấy:
- Gateway timeout
- Teams retry tin nhắn (gây duplicate)
- Reply bị drop
OpenClaw xử lý điều này bằng cách return nhanh và gửi reply proactively, nhưng response rất chậm vẫn có thể gây vấn đề.
Formatting
Teams markdown hạn chế hơn Slack hoặc Discord:
- Formatting cơ bản hoạt động: bold, italic,
code, link - Markdown phức tạp (table, nested list) có thể không render đúng
- Adaptive Card được hỗ trợ cho poll và gửi card tùy ý (xem bên dưới)
Cấu hình
Các setting chính (xem /gateway/configuration cho các pattern channel chung):
channels.msteams.enabled: bật/tắt channel.channels.msteams.appId,channels.msteams.appPassword,channels.msteams.tenantId: bot credentials.channels.msteams.webhook.port(mặc định3978)channels.msteams.webhook.path(mặc định/api/messages)channels.msteams.dmPolicy:pairing | allowlist | open | disabled(mặc định: pairing)channels.msteams.allowFrom: allowlist cho DM (AAD object ID, UPN, hoặc display name). Wizard resolve name thành ID trong setup khi có Graph access.channels.msteams.textChunkLimit: kích thước chunk text outbound.channels.msteams.chunkMode:length(mặc định) hoặcnewlineđể split theo dòng trống (paragraph boundary) trước khi length chunking.channels.msteams.mediaAllowHosts: allowlist cho inbound attachment host (mặc định là Microsoft/Teams domain).channels.msteams.requireMention: cần @mention trong channel/group (mặc định true).channels.msteams.replyStyle:thread | top-level(xem Reply Style).channels.msteams.teams.<teamId>.replyStyle: override theo team.channels.msteams.teams.<teamId>.requireMention: override theo team.channels.msteams.teams.<teamId>.tools: default per-team tool policy override (allow/deny/alsoAllow) dùng khi thiếu channel override.channels.msteams.teams.<teamId>.toolsBySender: default per-team per-sender tool policy override (hỗ trợ wildcard"*").channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle: override theo channel.channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention: override theo channel.channels.msteams.teams.<teamId>.channels.<conversationId>.tools: per-channel tool policy override (allow/deny/alsoAllow).channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender: per-channel per-sender tool policy override (hỗ trợ wildcard"*").channels.msteams.sharePointSiteId: SharePoint site ID cho upload file trong group chat/channel (xem Gửi file trong group chat).
Routing & Session
- Session key theo format agent chuẩn (xem /concepts/session):
- Tin nhắn trực tiếp chia sẻ main session (
agent:<agentId>:<mainKey>). - Tin nhắn channel/group dùng conversation id:
agent:<agentId>:msteams:channel:<conversationId>agent:<agentId>:msteams:group:<conversationId>
- Tin nhắn trực tiếp chia sẻ main session (
Reply Style: Thread vs Post
Teams gần đây giới thiệu hai kiểu UI channel trên cùng một data model:
| Style | Mô tả | replyStyle khuyên dùng |
|---|---|---|
| Posts (classic) | Tin nhắn hiển thị dạng card với reply thread bên dưới | thread (mặc định) |
| Threads (giống Slack) | Tin nhắn chảy tuyến tính, giống Slack hơn | top-level |
Vấn đề: Teams API không expose kiểu UI nào mà channel đang dùng. Nếu các bạn dùng sai replyStyle:
threadtrong channel kiểu Threads → reply hiển thị nested khó hiểutop-leveltrong channel kiểu Posts → reply hiển thị như post riêng thay vì trong thread
Giải pháp: Cấu hình replyStyle theo từng channel dựa trên cách channel được setup:
{
"msteams": {
"replyStyle": "thread",
"teams": {
"19:[email protected]": {
"channels": {
"19:[email protected]": {
"replyStyle": "top-level"
}
}
}
}
}
}
Attachment & Hình ảnh
Hạn chế hiện tại:
- DM: Hình ảnh và file attachment hoạt động qua Teams bot file API.
- Channel/group: Attachment nằm trong M365 storage (SharePoint/OneDrive). Webhook payload chỉ bao gồm HTML stub, không phải file byte thực tế. Cần quyền Graph API để download channel attachment.
Không có quyền Graph, tin nhắn channel có hình ảnh sẽ được nhận dưới dạng text-only (nội dung hình ảnh không thể truy cập bởi bot).
Mặc định, OpenClaw chỉ download media từ Microsoft/Teams hostname. Override bằng channels.msteams.mediaAllowHosts (dùng ["*"] để cho phép bất kỳ host nào).
Gửi file trong group chat
Bot có thể gửi file trong DM bằng FileConsentCard flow (có sẵn). Tuy nhiên, gửi file trong group chat/channel cần setup thêm:
| Context | Cách gửi file | Setup cần thiết |
|---|---|---|
| DM | FileConsentCard → user chấp nhận → bot upload | Hoạt động ngay |
| Group chat/channel | Upload lên SharePoint → chia sẻ link | Cần sharePointSiteId + quyền Graph |
| Hình ảnh (bất kỳ context) | Base64-encoded inline | Hoạt động ngay |
Tại sao group chat cần SharePoint
Bot không có OneDrive drive cá nhân (Graph API endpoint /me/drive không hoạt động với application identity). Để gửi file trong group chat/channel, bot upload lên SharePoint site và tạo sharing link.
Setup
-
Thêm quyền Graph API trong Entra ID (Azure AD) → App Registration:
Sites.ReadWrite.All(Application) - upload file lên SharePointChat.Read.All(Application) - tùy chọn, cho phép sharing link theo user
-
Grant admin consent cho tenant.
-
Lấy SharePoint site ID của bạn:
# Qua Graph Explorer hoặc curl với token hợp lệ: curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}" # Ví dụ: cho site tại "contoso.sharepoint.com/sites/BotFiles" curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/BotFiles" # Response bao gồm: "id": "contoso.sharepoint.com,guid1,guid2" -
Cấu hình OpenClaw:
{ channels: { msteams: { // ... config khác ... sharePointSiteId: "contoso.sharepoint.com,guid1,guid2", }, }, }
Hành vi chia sẻ
| Quyền | Hành vi chia sẻ |
|---|---|
Chỉ Sites.ReadWrite.All | Sharing link toàn tổ chức (bất kỳ ai trong org đều truy cập được) |
Sites.ReadWrite.All + Chat.Read.All | Sharing link theo user (chỉ thành viên chat truy cập được) |
Sharing theo user an toàn hơn vì chỉ người tham gia chat mới truy cập được file. Nếu thiếu quyền Chat.Read.All, bot sẽ fallback về sharing toàn tổ chức.
Hành vi fallback
| Tình huống | Kết quả |
|---|---|
Group chat + file + đã config sharePointSiteId | Upload lên SharePoint, gửi sharing link |
Group chat + file + không có sharePointSiteId | Thử upload OneDrive (có thể fail), chỉ gửi text |
| Personal chat + file | FileConsentCard flow (hoạt động không cần SharePoint) |
| Bất kỳ context + hình ảnh | Base64-encoded inline (hoạt động không cần SharePoint) |
Vị trí lưu file
File được upload sẽ lưu trong thư mục /OpenClawShared/ trong default document library của SharePoint site đã cấu hình.
Poll (Adaptive Cards)
OpenClaw gửi Teams poll dưới dạng Adaptive Card (không có native Teams poll API).
- CLI:
openclaw message poll --channel msteams --target conversation:<id> ... - Vote được ghi lại bởi gateway trong
~/.openclaw/msteams-polls.json. - Gateway phải online để ghi vote.
- Poll chưa tự động post kết quả tổng hợp (kiểm tra store file nếu cần).
Adaptive Card (tùy ý)
Gửi bất kỳ Adaptive Card JSON nào tới Teams user hoặc conversation bằng tool message hoặc CLI.
Tham số card chấp nhận object Adaptive Card JSON. Khi có card, text tin nhắn là tùy chọn.
Agent tool:
{
"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!"}]}'
Xem tài liệu Adaptive Cards cho schema và ví dụ. Để biết chi tiết format target, xem Target formats bên dưới.
Target formats
MSTeams target dùng prefix để phân biệt giữa user và conversation:
| Loại target | Format | Ví dụ |
|---|---|---|
| User (theo ID) | user:<aad-object-id> | user:40a1a0ed-4ff2-4164-a219-55518990c197 |
| User (theo tên) | user:<display-name> | user:John Smith (cần Graph API) |
| Group/channel | conversation:<conversation-id> | conversation:19:[email protected] |
| Group/channel (raw) | <conversation-id> | 19:[email protected] (nếu chứa @thread) |
Ví dụ CLI:
# Gửi tới user theo ID
openclaw message send --channel msteams --target "user:40a1a0ed-..." --message "Hello"
# Gửi tới user theo display name (trigger Graph API lookup)
openclaw message send --channel msteams --target "user:John Smith" --message "Hello"
# Gửi tới group chat hoặc channel
openclaw message send --channel msteams --target "conversation:19:[email protected]" --message "Hello"
# Gửi Adaptive Card tới conversation
openclaw message send --channel msteams --target "conversation:19:[email protected]" \
--card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello"}]}'
Ví dụ Agent tool:
{
"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" }]
}
}
Lưu ý: Không có prefix user:, tên sẽ mặc định resolve thành group/team. Luôn dùng user: khi target người theo display name.
Proactive messaging
- Tin nhắn proactive chỉ có thể sau khi user đã tương tác, vì chúng ta lưu conversation reference tại thời điểm đó.
- Xem
/gateway/configurationchodmPolicyvà allowlist gating.
Team và Channel ID (Lỗi thường gặp)
Tham số groupId trong Teams URL KHÔNG PHẢI là team ID dùng cho cấu hình. Trích xuất ID từ URL path thay vì:
Team URL:
https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
└────────────────────────────┘
Team ID (URL-decode cái này)
Channel URL:
https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
└─────────────────────────┘
Channel ID (URL-decode cái này)
Cho config:
- Team ID = path segment sau
/team/(URL-decoded, ví dụ:19:[email protected]) - Channel ID = path segment sau
/channel/(URL-decoded) - Bỏ qua tham số query
groupId
Private Channel
Bot có hỗ trợ hạn chế trong private channel:
| Tính năng | Standard Channel | Private Channel |
|---|---|---|
| Cài đặt bot | Có | Hạn chế |
| Tin nhắn real-time (webhook) | Có | Có thể không hoạt động |
| Quyền RSC | Có | Có thể hoạt động khác |
| @mention | Có | Nếu bot có thể truy cập |
| Graph API history | Có | Có (với quyền) |
Giải pháp nếu private channel không hoạt động:
- Dùng standard channel cho tương tác bot
- Dùng DM - user luôn có thể nhắn tin trực tiếp với bot
- Dùng Graph API cho truy cập lịch sử (cần
ChannelMessage.Read.All)
Troubleshooting
Vấn đề thường gặp
- Hình ảnh không hiển thị trong channel: Thiếu quyền Graph hoặc admin consent. Cài lại Teams app và thoát hoàn toàn/mở lại Teams.
- Không có response trong channel: mention là bắt buộc mặc định; set
channels.msteams.requireMention=falsehoặc cấu hình theo team/channel. - Version mismatch (Teams vẫn hiển thị manifest cũ): gỡ + cài lại app và thoát hoàn toàn Teams để refresh.
- 401 Unauthorized từ webhook: Dự kiến khi test thủ công không có Azure JWT - nghĩa là endpoint có thể truy cập nhưng auth fail. Dùng Azure Web Chat để test đúng cách.
Lỗi upload manifest
- “Icon file cannot be empty”: Manifest tham chiếu đến icon file có 0 byte. Tạo PNG icon hợp lệ (32x32 cho
outline.png, 192x192 chocolor.png). - “webApplicationInfo.Id already in use”: App vẫn được cài trong team/chat khác. Tìm và gỡ cài đặt trước, hoặc đợi 5-10 phút để propagation.
- “Something went wrong” khi upload: Upload qua https://admin.teams.microsoft.com thay vì, mở browser DevTools (F12) → tab Network, và check response body để xem lỗi thực tế.
- Sideload fail: Thử “Upload an app to your org’s app catalog” thay vì “Upload a custom app” - cách này thường bypass sideload restriction.
Quyền RSC không hoạt động
- Xác minh
webApplicationInfo.idkhớp chính xác với App ID của bot - Re-upload app và cài lại trong team/chat
- Kiểm tra xem org admin có chặn quyền RSC không
- Xác nhận bạn đang dùng đúng scope:
ChannelMessage.Read.Groupcho team,ChatMessage.Read.Chatcho group chat
Tài liệu tham khảo
- Create Azure Bot - Hướng dẫn setup Azure Bot
- Teams Developer Portal - tạo/quản lý Teams app
- Teams app manifest schema
- Receive channel messages with RSC
- RSC permissions reference
- Teams bot file handling (channel/group cần Graph)
- Proactive messaging