Mainstream messaging
Microsoft Teams
Trạng thái: hỗ trợ văn bản + tệp đính kèm trong DM; gửi tệp trong kênh/nhóm yêu cầu sharePointSiteId + quyền Graph (xem Gửi tệp trong cuộc trò chuyện nhóm). Poll được gửi qua Adaptive Cards. Các thao tác trên tin nhắn cung cấp upload-file rõ ràng cho các lượt gửi ưu tiên tệp.
Plugin đi kèm
Microsoft Teams được phát hành dưới dạng Plugin đi kèm trong các bản phát hành OpenClaw hiện tại, nên không cần cài đặt riêng trong bản dựng đóng gói thông thường.
Nếu bạn đang dùng bản dựng cũ hơn hoặc bản cài đặt tùy chỉnh loại trừ Teams đi kèm, hãy cài đặt trực tiếp gói npm:
openclaw plugins install @openclaw/msteams
Dùng gói trần để theo thẻ phát hành chính thức hiện tại. Chỉ ghim một phiên bản chính xác khi bạn cần bản cài đặt có thể tái lập.
Bản checkout cục bộ (khi chạy từ một repo git):
openclaw plugins install ./path/to/local/msteams-plugin
Chi tiết: Plugins
Thiết lập nhanh
@microsoft/teams.cli xử lý đăng ký bot, tạo manifest và tạo thông tin xác thực trong một lệnh duy nhất.
1. Cài đặt và đăng nhập
npm install -g @microsoft/teams.cli@preview
teams login
teams status # verify you're logged in and see your tenant info
2. Khởi động một tunnel (Teams không thể truy cập localhost)
Cài đặt và xác thực devtunnel CLI nếu bạn chưa làm (hướng dẫn bắt đầu).
# One-time setup (persistent URL across sessions):
devtunnel create my-openclaw-bot --allow-anonymous
devtunnel 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
Các lựa chọn thay thế: ngrok http 3978 hoặc tailscale funnel 3978 (nhưng các lựa chọn này có thể đổi URL ở mỗi phiên).
3. Tạo ứng dụng
teams app create \
--name "OpenClaw" \
--endpoint "https://<your-tunnel-url>/api/messages"
Lệnh duy nhất này:
- Tạo một ứng dụng Entra ID (Azure AD)
- Tạo một client secret
- Dựng và tải lên manifest ứng dụng Teams (kèm biểu tượng)
- Đăng ký bot (mặc định do Teams quản lý - không cần gói đăng ký Azure)
Đầu ra sẽ hiển thị CLIENT_ID, CLIENT_SECRET, TENANT_ID và một Teams App ID - hãy ghi lại các giá trị này cho các bước tiếp theo. Nó cũng đề nghị cài đặt ứng dụng trực tiếp trong Teams.
4. Cấu hình OpenClaw bằng thông tin xác thực từ đầu ra:
{
channels: {
msteams: {
enabled: true,
appId: "<CLIENT_ID>",
appPassword: "<CLIENT_SECRET>",
tenantId: "<TENANT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Hoặc dùng trực tiếp biến môi trường: MSTEAMS_APP_ID, MSTEAMS_APP_PASSWORD, MSTEAMS_TENANT_ID.
5. Cài đặt ứng dụng trong Teams
teams app create sẽ nhắc bạn cài đặt ứng dụng - chọn "Install in Teams". Nếu bạn đã bỏ qua, bạn có thể lấy liên kết sau:
teams app get <teamsAppId> --install-link
6. Xác minh mọi thứ hoạt động
teams app doctor <teamsAppId>
Lệnh này chạy chẩn đoán trên đăng ký bot, cấu hình ứng dụng AAD, tính hợp lệ của manifest và thiết lập SSO.
Với triển khai production, hãy cân nhắc dùng xác thực liên kết (chứng chỉ hoặc managed identity) thay vì client secret.
Mục tiêu
- Trò chuyện với OpenClaw qua DM Teams, cuộc trò chuyện nhóm hoặc kênh.
- Giữ định tuyến mang tính xác định: phản hồi luôn quay lại kênh mà chúng đến từ đó.
- Mặc định dùng hành vi kênh an toàn (yêu cầu nhắc tên trừ khi được cấu hình khác).
Ghi cấu hình
Theo mặc định, Microsoft Teams được phép ghi các cập nhật cấu hình được kích hoạt bởi /config set|unset (yêu cầu commands.config: true).
Tắt bằng:
{
channels: { msteams: { configWrites: false } },
}
Kiểm soát truy cập (DM + nhóm)
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.allowFromnên dùng ID đối tượng AAD ổn định.- Không dựa vào việc khớp UPN/tên hiển thị cho allowlist - chúng có thể thay đổi. OpenClaw tắt khớp tên trực tiếp theo mặc định; bật rõ ràng bằng
channels.msteams.dangerouslyAllowNameMatching: true. - Trình hướng dẫn có thể phân giải tên thành ID qua Microsoft Graph khi thông tin xác thực cho phép.
Truy cập nhóm
- Mặc định:
channels.msteams.groupPolicy = "allowlist"(bị chặn trừ khi bạn thêmgroupAllowFrom). Dùngchannels.defaults.groupPolicyđể ghi đè mặc định khi chưa đặt. channels.msteams.groupAllowFromkiểm soát người gửi nào có thể kích hoạt trong cuộc trò chuyện nhóm/kênh (dự phòng vềchannels.msteams.allowFrom).- Đặt
groupPolicy: "open"để cho phép bất kỳ thành viên nào (mặc định vẫn được kiểm soát bằng nhắc tên). - Để không cho phép kênh nào, đặt
channels.msteams.groupPolicy: "disabled".
Ví dụ:
{
channels: {
msteams: {
groupPolicy: "allowlist",
groupAllowFrom: ["[email protected]"],
},
},
}
Teams + allowlist kênh
- Giới hạn phạm vi phản hồi nhóm/kênh bằng cách liệt kê teams và kênh dưới
channels.msteams.teams. - Khóa nên dùng ID cuộc trò chuyện Teams ổn định từ liên kết Teams, không dùng tên hiển thị có thể thay đổi.
- Khi
groupPolicy="allowlist"và có allowlist teams, chỉ các teams/kênh được liệt kê mới được chấp nhận (được kiểm soát bằng nhắc tên). - Trình hướng dẫn cấu hình chấp nhận các mục
Team/Channelvà lưu chúng cho bạn. - Khi khởi động, OpenClaw phân giải tên allowlist team/kênh và người dùng thành ID (khi quyền Graph cho phép)
và ghi lại ánh xạ; tên team/kênh chưa phân giải được giữ nguyên như đã nhập nhưng mặc định bị bỏ qua khi định tuyến, trừ khi bật
channels.msteams.dangerouslyAllowNameMatching: true.
Ví dụ:
{
channels: {
msteams: {
groupPolicy: "allowlist",
teams: {
"My Team": {
channels: {
General: { requireMention: true },
},
},
},
},
},
}
Thiết lập thủ công (không dùng Teams CLI)
Nếu bạn không thể dùng Teams CLI, bạn có thể thiết lập bot thủ công qua Azure Portal.
Cách hoạt động
- Đảm bảo Microsoft Teams Plugin khả dụng (đi kèm trong các bản phát hành hiện tại).
- Tạo một Azure Bot (App ID + secret + tenant ID).
- Dựng một gói ứng dụng Teams tham chiếu đến bot và bao gồm các quyền RSC bên dưới.
- Tải lên/cài đặt ứng dụng Teams vào một team (hoặc phạm vi cá nhân cho DM).
- Cấu hình
msteamstrong~/.openclaw/openclaw.json(hoặc biến môi trường) và khởi động gateway. - Gateway mặc định lắng nghe lưu lượng Webhook Bot Framework trên
/api/messages.
Bước 1: Tạo Azure Bot
-
Đi tới Tạo Azure Bot
-
Điền vào thẻ Basics:
Trường Giá trị Bot handle Tên bot của bạn, ví dụ openclaw-msteams(phải là duy nhất)Subscription Chọn gói đăng ký Azure của bạn Resource group Tạo mới hoặc dùng nhóm hiện có Pricing tier Free cho phát triển/kiểm thử Type of App Single Tenant (khuyến nghị - xem ghi chú bên dưới) Creation type Create new Microsoft App ID
- Nhấp Review + create → Create (chờ khoảng 1-2 phút)
Bước 2: Lấy thông tin xác thực
- Đi tới tài nguyên Azure Bot của bạn → Configuration
- Sao chép Microsoft App ID → đây là
appIdcủa bạn - Nhấp Manage Password → đi tới App Registration
- Trong Certificates & secrets → New client secret → sao chép Value → đây là
appPasswordcủa bạn - Đi tới Overview → sao chép Directory (tenant) ID → đây là
tenantIdcủa bạn
Bước 3: Cấu hình Messaging Endpoint
- Trong Azure Bot → Configuration
- Đặt Messaging endpoint thành URL Webhook của bạn:
- Production:
https://your-domain.com/api/messages - Phát triển cục bộ: Dùng tunnel (xem Phát triển cục bộ bên dưới)
- Production:
Bước 4: Bật kênh Teams
- Trong Azure Bot → Channels
- Nhấp Microsoft Teams → Configure → Save
- Chấp nhận Điều khoản dịch vụ
Bước 5: Dựng Teams App Manifest
- Bao gồm một mục
botvớibotId = <App ID>. - Phạm vi:
personal,team,groupChat. supportsFiles: true(bắt buộc để xử lý tệp trong phạm vi cá nhân).- Thêm quyền RSC (xem Quyền RSC).
- Tạo biểu tượng:
outline.png(32x32) vàcolor.png(192x192). - Nén cả ba tệp lại với nhau:
manifest.json,outline.png,color.png.
Bước 6: Cấu hình OpenClaw
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
appPassword: "<APP_PASSWORD>",
tenantId: "<TENANT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Biến môi trường: MSTEAMS_APP_ID, MSTEAMS_APP_PASSWORD, MSTEAMS_TENANT_ID.
Bước 7: Chạy Gateway
Kênh Teams tự động khởi động khi Plugin khả dụng và cấu hình msteams tồn tại cùng thông tin xác thực.
Xác thực liên kết (chứng chỉ cộng với managed identity)
Đã thêm trong 2026.4.11
Với triển khai production, OpenClaw hỗ trợ xác thực liên kết như một phương án bảo mật hơn thay cho client secret. Có hai phương thức:
Tùy chọn A: Xác thực dựa trên chứng chỉ
Dùng chứng chỉ PEM đã đăng ký với app registration Entra ID của bạn.
Thiết lập:
- Tạo hoặc lấy một chứng chỉ (định dạng PEM với khóa riêng).
- Trong Entra ID → App Registration → Certificates & secrets → Certificates → Tải lên chứng chỉ công khai.
Cấu hình:
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
tenantId: "<TENANT_ID>",
authType: "federated",
certificatePath: "/path/to/cert.pem",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Biến môi trường:
MSTEAMS_AUTH_TYPE=federatedMSTEAMS_CERTIFICATE_PATH=/path/to/cert.pem
Tùy chọn B: Azure Managed Identity
Dùng Azure Managed Identity để xác thực không mật khẩu. Cách này lý tưởng cho triển khai trên hạ tầng Azure (AKS, App Service, Azure VMs) nơi có managed identity.
Cách hoạt động:
- Pod/VM của bot có managed identity (do hệ thống gán hoặc do người dùng gán).
- Một federated identity credential liên kết managed identity với app registration Entra ID.
- Khi chạy, OpenClaw dùng
@azure/identityđể lấy token từ endpoint Azure IMDS (169.254.169.254). - Token được truyền tới Teams SDK để xác thực bot.
Điều kiện tiên quyết:
- Hạ tầng Azure đã bật managed identity (AKS workload identity, App Service, VM)
- Federated identity credential được tạo trên app registration Entra ID
- Truy cập mạng tới IMDS (
169.254.169.254:80) từ pod/VM
Cấu hình (managed identity do hệ thống gán):
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
tenantId: "<TENANT_ID>",
authType: "federated",
useManagedIdentity: true,
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Cấu hình (danh tính được quản lý do người dùng gán):
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
tenantId: "<TENANT_ID>",
authType: "federated",
useManagedIdentity: true,
managedIdentityClientId: "<MI_CLIENT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Biến môi trường:
MSTEAMS_AUTH_TYPE=federatedMSTEAMS_USE_MANAGED_IDENTITY=trueMSTEAMS_MANAGED_IDENTITY_CLIENT_ID=<client-id>(chỉ dành cho loại do người dùng gán)
Thiết lập danh tính workload cho AKS
Đối với các triển khai AKS dùng danh tính workload:
-
Bật danh tính workload trên cụm AKS của bạn.
-
Tạo thông tin xác thực danh tính liên kết trên đăng ký ứng dụng Entra ID:
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"] }' -
Chú thích tài khoản dịch vụ Kubernetes bằng ID máy khách của ứng dụng:
apiVersion: v1 kind: ServiceAccount metadata: name: my-bot-sa annotations: azure.workload.identity/client-id: "<APP_CLIENT_ID>" -
Gắn nhãn pod để chèn danh tính workload:
metadata: labels: azure.workload.identity/use: "true" -
Đảm bảo quyền truy cập mạng đến IMDS (
169.254.169.254) - nếu dùng NetworkPolicy, hãy thêm quy tắc egress cho phép lưu lượng đến169.254.169.254/32trên cổng 80.
So sánh loại xác thực
| Phương thức | Cấu hình | Ưu điểm | Nhược điểm |
|---|---|---|---|
| Bí mật máy khách | appPassword |
Thiết lập đơn giản | Cần xoay vòng bí mật, kém an toàn hơn |
| Chứng chỉ | authType: "federated" + certificatePath |
Không có bí mật dùng chung qua mạng | Tốn công quản lý chứng chỉ |
| Danh tính được quản lý | authType: "federated" + useManagedIdentity |
Không cần mật khẩu, không phải quản lý bí mật | Cần hạ tầng Azure |
Hành vi mặc định: Khi chưa đặt authType, OpenClaw mặc định dùng xác thực bằng bí mật máy khách. Các cấu hình hiện có tiếp tục hoạt động mà không cần thay đổi.
Phát triển cục bộ (tunneling)
Teams không thể truy cập localhost. Hãy dùng một dev tunnel bền vững để URL của bạn giữ nguyên giữa các phiên:
# One-time setup:
devtunnel create my-openclaw-bot --allow-anonymous
devtunnel port create my-openclaw-bot -p 3978 --protocol auto
# Each dev session:
devtunnel host my-openclaw-bot
Các lựa chọn thay thế: ngrok http 3978 hoặc tailscale funnel 3978 (URL có thể thay đổi ở mỗi phiên).
Nếu URL tunnel của bạn thay đổi, hãy cập nhật endpoint:
teams app update <teamsAppId> --endpoint "https://<new-url>/api/messages"
Kiểm thử bot
Chạy chẩn đoán:
teams app doctor <teamsAppId>
Kiểm tra đăng ký bot, ứng dụng AAD, manifest và cấu hình SSO trong một lượt.
Gửi tin nhắn kiểm thử:
- Cài đặt ứng dụng Teams (dùng liên kết cài đặt từ
teams app get <id> --install-link) - Tìm bot trong Teams và gửi DM
- Kiểm tra nhật ký Gateway để xem hoạt động đến
Biến môi trường
Thay vào đó, mọi khóa cấu hình đều có thể được đặt qua biến môi trường:
MSTEAMS_APP_IDMSTEAMS_APP_PASSWORDMSTEAMS_TENANT_IDMSTEAMS_AUTH_TYPE(tùy chọn:"secret"hoặc"federated")MSTEAMS_CERTIFICATE_PATH(liên kết + chứng chỉ)MSTEAMS_CERTIFICATE_THUMBPRINT(tùy chọn, không bắt buộc cho xác thực)MSTEAMS_USE_MANAGED_IDENTITY(liên kết + danh tính được quản lý)MSTEAMS_MANAGED_IDENTITY_CLIENT_ID(chỉ dành cho MI do người dùng gán)
Hành động thông tin thành viên
OpenClaw cung cấp hành động member-info dựa trên Graph cho Microsoft Teams để các agent và tự động hóa có thể phân giải chi tiết thành viên kênh (tên hiển thị, email, vai trò) trực tiếp từ Microsoft Graph.
Yêu cầu:
- Quyền RSC
Member.Read.Group(đã có trong manifest được khuyến nghị) - Đối với tra cứu giữa các team: quyền Graph Application
User.Read.Allvới sự đồng ý của quản trị viên
Hành động này được kiểm soát bằng channels.msteams.actions.memberInfo (mặc định: bật khi có thông tin xác thực Graph).
Ngữ cảnh lịch sử
channels.msteams.historyLimitkiểm soát số lượng tin nhắn kênh/nhóm gần đây được đưa vào prompt.- Quay về dùng
messages.groupChat.historyLimit. Đặt0để tắt (mặc định 50). - Lịch sử thread được lấy về sẽ được lọc theo allowlist người gửi (
allowFrom/groupAllowFrom), vì vậy việc gieo ngữ cảnh thread chỉ bao gồm tin nhắn từ những người gửi được phép. - Ngữ cảnh tệp đính kèm được trích dẫn (
ReplyTo*bắt nguồn từ HTML trả lời của Teams) hiện được truyền nguyên như đã nhận. - Nói cách khác, allowlist kiểm soát ai có thể kích hoạt agent; hiện nay chỉ một số đường dẫn ngữ cảnh bổ sung cụ thể được lọc.
- Có thể giới hạn lịch sử DM bằng
channels.msteams.dmHistoryLimit(lượt của người dùng). Ghi đè theo từng người dùng:channels.msteams.dms["<user_id>"].historyLimit.
Quyền RSC Teams hiện tại (manifest)
Đây là các quyền resourceSpecific hiện có trong manifest ứng dụng Teams của chúng tôi. Chúng chỉ áp dụng trong team/cuộc trò chuyện nơi ứng dụng được cài đặt.
Đối với kênh (phạm vi team):
ChannelMessage.Read.Group(Application) - nhận tất cả tin nhắn kênh 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)
Đối với cuộc trò chuyện nhóm:
ChatMessage.Read.Chat(Application) - nhận tất cả tin nhắn cuộc trò chuyện nhóm mà không cần @mention
Để thêm quyền RSC qua Teams CLI:
teams app rsc add <teamsAppId> ChannelMessage.Read.Group --type Application
Ví dụ manifest Teams (đã biên tập)
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 bề mặt bạn dự định dùng (personal,team,groupChat).bots[].supportsFiles: truelà bắt buộc để xử lý tệp trong phạm vi cá nhân.authorization.permissions.resourceSpecificphải bao gồm quyền đọc/gửi kênh nếu bạn muốn lưu lượng kênh.
Cập nhật một ứng dụng hiện có
Để cập nhật ứng dụng Teams đã được cài đặt (ví dụ: để thêm quyền RSC):
# Download, edit, and re-upload the manifest
teams app manifest download <teamsAppId> manifest.json
# Edit manifest.json locally...
teams app manifest upload manifest.json <teamsAppId>
# Version is auto-bumped if content changed
Sau khi cập nhật, hãy cài đặt lại ứng dụng trong từng team để các quyền mới có hiệu lực, và thoát hoàn toàn rồi mở lại Teams (không chỉ đóng cửa sổ) để xóa siêu dữ liệu ứng dụng đã lưu trong bộ nhớ đệm.
Cập nhật manifest thủ công (không dùng CLI)
- Cập nhật
manifest.jsoncủa bạn với các thiết lập mới - Tăng trường
version(ví dụ:1.0.0→1.1.0) - Nén lại manifest cùng với các biểu tượng (
manifest.json,outline.png,color.png) - Tải lên tệp zip mới:
- Teams Admin Center: Ứng dụng Teams → Quản lý ứng dụng → tìm ứng dụng của bạn → Tải lên phiên bản mới
- Sideload: Trong Teams → Ứng dụng → Quản lý ứng dụng của bạn → Tải lên ứng dụng tùy chỉnh
Khả năng: chỉ RSC so với Graph
Chỉ với Teams RSC (ứng dụng đã cài đặt, không có quyền Graph API)
Hoạt động:
- Đọc nội dung văn bản của tin nhắn kênh.
- Gửi nội dung văn bản của tin nhắn kênh.
- Nhận tệp đính kèm cá nhân (DM).
Không hoạt động:
- Nội dung hình ảnh hoặc tệp trong kênh/nhóm (payload chỉ bao gồm stub HTML).
- Tải xuống tệp đính kèm được lưu trong SharePoint/OneDrive.
- Đọc lịch sử tin nhắn (ngoài sự kiện Webhook trực tiếp).
Với Teams RSC + quyền Microsoft Graph Application
Bổ sung:
- Tải xuống nội dung được lưu trữ (hình ảnh được dán vào tin nhắn).
- Tải xuống tệp đính kèm được lưu trong SharePoint/OneDrive.
- Đọc lịch sử tin nhắn kênh/cuộc trò chuyện qua Graph.
RSC so với Graph API
| Khả năng | Quyền RSC | Graph API |
|---|---|---|
| Tin nhắn thời gian thực | Có (qua Webhook) | Không (chỉ polling) |
| Tin nhắn lịch sử | Không | Có (có thể truy vấn lịch sử) |
| Độ phức tạp thiết lập | Chỉ manifest ứng dụng | Cần sự đồng ý của quản trị viên + luồng token |
| Hoạt động khi ngoại tuyến | Không (phải đang chạy) | Có (truy vấn bất cứ lúc nào) |
Tóm lại: RSC dùng để lắng nghe thời gian thực; Graph API dùng để truy cập lịch sử. Để bắt kịp các tin nhắn bị bỏ lỡ khi ngoại tuyến, bạn cần Graph API với ChannelMessage.Read.All (cần sự đồng ý của quản trị viên).
Media và lịch sử bật Graph (bắt buộc cho kênh)
Nếu bạn cần hình ảnh/tệp trong kênh hoặc muốn lấy lịch sử tin nhắn, bạn phải bật quyền Microsoft Graph và cấp sự đồng ý của quản trị viên.
- Trong App Registration của Entra ID (Azure AD), thêm quyền Application của Microsoft Graph:
ChannelMessage.Read.All(tệp đính kèm kênh + lịch sử)Chat.Read.AllhoặcChatMessage.Read.All(cuộc trò chuyện nhóm)
- Cấp sự đồng ý của quản trị viên cho tenant.
- Tăng phiên bản manifest của ứng dụng Teams, tải lên lại và cài đặt lại ứng dụng trong Teams.
- Thoát hoàn toàn rồi mở lại Teams để xóa siêu dữ liệu ứng dụng đã lưu trong bộ nhớ đệm.
Quyền bổ sung cho lượt đề cập người dùng: @mention người dùng hoạt động ngay từ đầu đối với người dùng trong cuộc trò chuyện. Tuy nhiên, nếu bạn muốn tìm kiếm động và đề cập những người dùng không ở trong cuộc trò chuyện hiện tại, hãy thêm quyền User.Read.All (Application) và cấp sự đồng ý của quản trị viên.
Hạn chế đã biết
Hết thời gian chờ Webhook
Teams gửi tin nhắn qua HTTP Webhook. Nếu quá trình xử lý mất quá lâu (ví dụ: phản hồi LLM chậm), bạn có thể thấy:
- Gateway hết thời gian chờ
- Teams thử lại tin nhắn (gây trùng lặp)
- Phản hồi bị bỏ
OpenClaw xử lý việc này bằng cách trả về nhanh và chủ động gửi phản hồi, nhưng các phản hồi rất chậm vẫn có thể gây ra sự cố.
Định dạng
Markdown của Teams bị giới hạn hơn Slack hoặc Discord:
- Định dạng cơ bản hoạt động: in đậm, in nghiêng,
code, liên kết - Markdown phức tạp (bảng, danh sách lồng nhau) có thể không hiển thị đúng
- Adaptive Cards được hỗ trợ cho thăm dò ý kiến và gửi phần trình bày ngữ nghĩa (xem bên dưới)
Cấu hình
Các cài đặt chính (xem /gateway/configuration để biết các mẫu kênh dùng chung):
channels.msteams.enabled: bật/tắt kênh.channels.msteams.appId,channels.msteams.appPassword,channels.msteams.tenantId: thông tin xác thực của bot.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: danh sách cho phép DM (khuyến nghị dùng ID đối tượng AAD). Trình hướng dẫn phân giải tên thành ID trong quá trình thiết lập khi có quyền truy cập Graph.channels.msteams.dangerouslyAllowNameMatching: công tắc phá kính để bật lại việc khớp UPN/tên hiển thị có thể thay đổi và định tuyến trực tiếp theo tên nhóm/kênh.channels.msteams.textChunkLimit: kích thước đoạn văn bản gửi đi.channels.msteams.chunkMode:length(mặc định) hoặcnewlineđể tách theo dòng trống (ranh giới đoạn văn) trước khi chia đoạn theo độ dài.channels.msteams.mediaAllowHosts: danh sách cho phép các máy chủ tệp đính kèm đầu vào (mặc định là các miền Microsoft/Teams).channels.msteams.mediaAuthAllowHosts: danh sách cho phép gắn tiêu đề Authorization khi thử lại phương tiện (mặc định là các máy chủ Graph + Bot Framework).channels.msteams.requireMention: yêu cầu @mention trong kênh/nhóm (mặc định true).channels.msteams.replyStyle:thread | top-level(xem Kiểu trả lời).channels.msteams.teams.<teamId>.replyStyle: ghi đè theo từng nhóm.channels.msteams.teams.<teamId>.requireMention: ghi đè theo từng nhóm.channels.msteams.teams.<teamId>.tools: các ghi đè chính sách công cụ mặc định theo từng nhóm (allow/deny/alsoAllow) được dùng khi thiếu ghi đè theo kênh.channels.msteams.teams.<teamId>.toolsBySender: các ghi đè chính sách công cụ mặc định theo từng nhóm và từng người gửi (hỗ trợ ký tự đại diện"*").channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle: ghi đè theo từng kênh.channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention: ghi đè theo từng kênh.channels.msteams.teams.<teamId>.channels.<conversationId>.tools: các ghi đè chính sách công cụ theo từng kênh (allow/deny/alsoAllow).channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender: các ghi đè chính sách công cụ theo từng kênh và từng người gửi (hỗ trợ ký tự đại diện"*").- Các khóa
toolsBySendernên dùng tiền tố tường minh:id:,e164:,username:,name:(các khóa cũ không có tiền tố vẫn chỉ ánh xạ tớiid:). channels.msteams.actions.memberInfo: bật hoặc tắt hành động thông tin thành viên dựa trên Graph (mặc định: bật khi có thông tin xác thực Graph).channels.msteams.authType: loại xác thực -"secret"(mặc định) hoặc"federated".channels.msteams.certificatePath: đường dẫn tới tệp chứng chỉ PEM (xác thực liên kết + chứng chỉ).channels.msteams.certificateThumbprint: dấu vân tay chứng chỉ (tùy chọn, không bắt buộc để xác thực).channels.msteams.useManagedIdentity: bật xác thực danh tính được quản lý (chế độ liên kết).channels.msteams.managedIdentityClientId: ID máy khách cho danh tính được quản lý do người dùng gán.channels.msteams.sharePointSiteId: ID site SharePoint để tải tệp lên trong cuộc trò chuyện nhóm/kênh (xem Gửi tệp trong cuộc trò chuyện nhóm).
Định tuyến và phiên
- Khóa phiên tuân theo định dạng tác nhân tiêu chuẩn (xem /concepts/session):
- Tin nhắn trực tiếp dùng chung phiên chính (
agent:<agentId>:<mainKey>). - Tin nhắn kênh/nhóm dùng ID cuộc trò chuyện:
agent:<agentId>:msteams:channel:<conversationId>agent:<agentId>:msteams:group:<conversationId>
- Tin nhắn trực tiếp dùng chung phiên chính (
Kiểu trả lời: chuỗi so với bài đăng
Teams gần đây đã giới thiệu hai kiểu giao diện kênh trên cùng một mô hình dữ liệu nền:
| Kiểu | Mô tả | replyStyle được khuyến nghị |
|---|---|---|
| Bài đăng (cổ điển) | Tin nhắn xuất hiện dưới dạng thẻ, với trả lời theo chuỗi bên dưới | thread (mặc định) |
| Chuỗi (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 cho biết một kênh dùng kiểu giao diện nào. Nếu bạn dùng sai replyStyle:
threadtrong kênh kiểu Chuỗi → câu trả lời xuất hiện lồng vào nhau một cách khó nhìntop-leveltrong kênh kiểu Bài đăng → câu trả lời xuất hiện thành các bài đăng cấp cao riêng biệt thay vì nằm trong chuỗi
Giải pháp: Cấu hình replyStyle theo từng kênh dựa trên cách kênh được thiết lập:
{
channels: {
msteams: {
replyStyle: "thread",
teams: {
"19:[email protected]": {
channels: {
"19:[email protected]": {
replyStyle: "top-level",
},
},
},
},
},
},
}
Tệp đính kèm và hình ảnh
Các giới hạn hiện tại:
- DM: Hình ảnh và tệp đính kèm hoạt động qua API tệp của bot Teams.
- Kênh/nhóm: Tệp đính kèm nằm trong bộ nhớ M365 (SharePoint/OneDrive). Tải trọng Webhook chỉ bao gồm một đoạn HTML giả lập, không phải byte tệp thực tế. Cần quyền Graph API để tải xuống tệp đính kèm của kênh.
- Đối với thao tác gửi ưu tiên tệp tường minh, dùng
action=upload-filevớimedia/filePath/path;messagetùy chọn trở thành văn bản/bình luận đi kèm, vàfilenameghi đè tên đã tải lên.
Nếu không có quyền Graph, tin nhắn kênh có hình ảnh sẽ được nhận dưới dạng chỉ văn bản (nội dung hình ảnh không thể truy cập được đối với bot).
Theo mặc định, OpenClaw chỉ tải phương tiện từ tên máy chủ Microsoft/Teams. Ghi đè bằng channels.msteams.mediaAllowHosts (dùng ["*"] để cho phép mọi máy chủ).
Tiêu đề Authorization chỉ được gắn cho các máy chủ trong channels.msteams.mediaAuthAllowHosts (mặc định là các máy chủ Graph + Bot Framework). Giữ danh sách này nghiêm ngặt (tránh các hậu tố nhiều tenant).
Gửi tệp trong cuộc trò chuyện nhóm
Bot có thể gửi tệp trong DM bằng luồng FileConsentCard (tích hợp sẵn). Tuy nhiên, gửi tệp trong cuộc trò chuyện nhóm/kênh cần thiết lập bổ sung:
| Ngữ cảnh | Cách tệp được gửi | Thiết lập cần có |
|---|---|---|
| DM | FileConsentCard → người dùng chấp nhận → bot tải lên | Hoạt động ngay |
| Cuộc trò chuyện nhóm/kênh | Tải lên SharePoint → chia sẻ liên kết | Cần sharePointSiteId + quyền Graph |
| Hình ảnh (mọi ngữ cảnh) | Mã hóa Base64 nội tuyến | Hoạt động ngay |
Vì sao cuộc trò chuyện nhóm cần SharePoint
Bot không có ổ OneDrive cá nhân (điểm cuối Graph API /me/drive không hoạt động cho danh tính ứng dụng). Để gửi tệp trong cuộc trò chuyện nhóm/kênh, bot tải lên một site SharePoint và tạo liên kết chia sẻ.
Thiết lập
-
Thêm quyền Graph API trong Entra ID (Azure AD) → App Registration:
Sites.ReadWrite.All(Application) - tải tệp lên SharePointChat.Read.All(Application) - tùy chọn, bật liên kết chia sẻ theo từng người dùng
-
Cấp sự đồng ý của quản trị viên cho tenant.
-
Lấy ID site SharePoint của bạn:
# 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" -
Cấu hình OpenClaw:
{ channels: { msteams: { // ... other config ... sharePointSiteId: "contoso.sharepoint.com,guid1,guid2", }, }, }
Hành vi chia sẻ
| Quyền | Hành vi chia sẻ |
|---|---|
Chỉ Sites.ReadWrite.All |
Liên kết chia sẻ toàn tổ chức (bất kỳ ai trong tổ chức đều có thể truy cập) |
Sites.ReadWrite.All + Chat.Read.All |
Liên kết chia sẻ theo từng người dùng (chỉ thành viên cuộc trò chuyện có thể truy cập) |
Chia sẻ theo từng người dùng bảo mật hơn vì chỉ những người tham gia cuộc trò chuyện mới có thể truy cập tệp. Nếu thiếu quyền Chat.Read.All, bot sẽ quay về chia sẻ toàn tổ chức.
Hành vi dự phòng
| Kịch bản | Kết quả |
|---|---|
Cuộc trò chuyện nhóm + tệp + đã cấu hình sharePointSiteId |
Tải lên SharePoint, gửi liên kết chia sẻ |
Cuộc trò chuyện nhóm + tệp + không có sharePointSiteId |
Thử tải lên OneDrive (có thể thất bại), chỉ gửi văn bản |
| Trò chuyện cá nhân + tệp | Luồng FileConsentCard (hoạt động không cần SharePoint) |
| Mọi ngữ cảnh + hình ảnh | Mã hóa Base64 nội tuyến (hoạt động không cần SharePoint) |
Vị trí lưu trữ tệp
Các tệp đã tải lên được lưu trong thư mục /OpenClawShared/ trong thư viện tài liệu mặc định của site SharePoint đã cấu hình.
Thăm dò ý kiến (Adaptive Cards)
OpenClaw gửi thăm dò ý kiến trên Teams dưới dạng Adaptive Cards (không có Teams poll API gốc).
- CLI:
openclaw message poll --channel msteams --target conversation:<id> ... - Phiếu bầu được Gateway ghi lại trong
~/.openclaw/msteams-polls.json. - Gateway phải luôn trực tuyến để ghi lại phiếu bầu.
- Thăm dò ý kiến chưa tự động đăng tóm tắt kết quả (kiểm tra tệp lưu trữ nếu cần).
Thẻ trình bày
Gửi tải trọng trình bày ngữ nghĩa tới người dùng hoặc cuộc trò chuyện Teams bằng công cụ message hoặc CLI. OpenClaw hiển thị chúng dưới dạng Teams Adaptive Cards từ hợp đồng trình bày chung.
Tham số presentation chấp nhận các khối ngữ nghĩa. Khi cung cấp presentation, văn bản tin nhắn là tùy chọn.
Công cụ tác nhân:
{
action: "send",
channel: "msteams",
target: "user:<id>",
presentation: {
title: "Hello",
blocks: [{ type: "text", text: "Hello!" }],
},
}
CLI:
openclaw message send --channel msteams \
--target "conversation:19:[email protected]" \
--presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello!"}]}'
Để biết chi tiết về định dạng đích, xem Định dạng đích bên dưới.
Định dạng đích
Đích MSTeams dùng tiền tố để phân biệt giữa người dùng và cuộc trò chuyện:
| Loại đích | Định dạng | Ví dụ |
|---|---|---|
| Người dùng (theo ID) | user:<aad-object-id> |
user:40a1a0ed-4ff2-4164-a219-55518990c197 |
| Người dùng (theo tên) | user:<display-name> |
user:John Smith (cần Graph API) |
| Nhóm/kênh | conversation:<conversation-id> |
conversation:19:[email protected] |
| Nhóm/kênh (thô) | <conversation-id> |
19:[email protected] (nếu chứa @thread) |
Ví dụ CLI:
# Send to a user by ID
openclaw 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 channel
openclaw message send --channel msteams --target "conversation:19:[email protected]" --message "Hello"
# Send a presentation card to a conversation
openclaw message send --channel msteams --target "conversation:19:[email protected]" \
--presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello"}]}'
Ví dụ về công cụ của tác tử:
{
action: "send",
channel: "msteams",
target: "user:John Smith",
message: "Hello!",
}
{
action: "send",
channel: "msteams",
target: "conversation:19:[email protected]",
presentation: {
title: "Hello",
blocks: [{ type: "text", text: "Hello" }],
},
}
Nhắn tin chủ động
- Tin nhắn chủ động chỉ khả dụng sau khi người dùng đã tương tác, vì chúng tôi lưu tham chiếu cuộc hội thoại tại thời điểm đó.
- Xem
/gateway/configurationđể biếtdmPolicyvà cơ chế kiểm soát bằng danh sách cho phép.
ID Team và Channel (Lỗi dễ gặp)
Tham số truy vấn groupId trong URL Teams KHÔNG phải là ID team dùng cho cấu hình. Hãy trích xuất ID từ đường dẫn URL thay vào đó:
URL Team:
https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
└────────────────────────────┘
ID cuộc hội thoại team (giải mã URL giá trị này)
URL Channel:
https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
└─────────────────────────┘
ID Channel (giải mã URL giá trị này)
Cho cấu hình:
- Khóa Team = phân đoạn đường dẫn sau
/team/(đã giải mã URL, ví dụ:19:[email protected]; tenant cũ hơn có thể hiển thị@thread.skype, giá trị này cũng hợp lệ) - Khóa Channel = phân đoạn đường dẫn sau
/channel/(đã giải mã URL) - Bỏ qua tham số truy vấn
groupIdcho định tuyến OpenClaw. Đây là ID nhóm Microsoft Entra, không phải ID cuộc hội thoại Bot Framework được dùng trong các hoạt động Teams đến.
Kênh riêng tư
Bot có hỗ trợ hạn chế trong kênh riêng tư:
| Tính năng | Kênh tiêu chuẩn | Kênh riêng tư |
|---|---|---|
| Cài đặt bot | Có | Hạn chế |
| Tin nhắn thời gian thực (Webhook) | Có | Có thể không hoạt động |
| Quyền RSC | Có | Có thể hoạt động khác |
| @mentions | Có | Nếu bot có thể truy cập |
| Lịch sử Graph API | Có | Có (với quyền phù hợp) |
Cách khắc phục nếu kênh riêng tư không hoạt động:
- Dùng kênh tiêu chuẩn cho các tương tác với bot
- Dùng DM - người dùng luôn có thể nhắn tin trực tiếp cho bot
- Dùng Graph API để truy cập lịch sử (yêu cầu
ChannelMessage.Read.All)
Khắc phục sự cố
Các vấn đề thường gặp
- Hình ảnh không hiển thị trong kênh: Thiếu quyền Graph hoặc sự đồng ý của quản trị viên. Cài đặt lại ứng dụng Teams và thoát hoàn toàn/mở lại Teams.
- Không có phản hồi trong kênh: theo mặc định cần có mention; đặt
channels.msteams.requireMention=falsehoặc cấu hình theo từng nhóm/kênh. - Phiên bản không khớp (Teams vẫn hiển thị manifest cũ): gỡ + thêm lại ứng dụng và thoát hoàn toàn khỏi Teams để làm mới.
- 401 Unauthorized từ Webhook: Dự kiến sẽ xảy ra khi kiểm thử thủ công mà không có Azure JWT - nghĩa là endpoint có thể truy cập được nhưng xác thực thất bại. Dùng Azure Web Chat để kiểm thử đúng cách.
Lỗi tải lên manifest
- "Icon file cannot be empty": Manifest tham chiếu đến các tệp biểu tượng có kích thước 0 byte. Tạo biểu tượng PNG hợp lệ (32x32 cho
outline.png, 192x192 chocolor.png). - "webApplicationInfo.Id already in use": Ứng dụng vẫn đang được cài đặt trong một nhóm/cuộc trò chuyện khác. Tìm và gỡ cài đặt trước, hoặc đợi 5-10 phút để thay đổi được lan truyền.
- "Something went wrong" khi tải lên: Thay vào đó, tải lên qua https://admin.teams.microsoft.com, mở DevTools của trình duyệt (F12) → thẻ Network, rồi kiểm tra phần nội dung phản hồi để xem lỗi thực tế.
- Sideload thất bại: Thử "Upload an app to your org's app catalog" thay vì "Upload a custom app" - cách này thường vượt qua các hạn chế sideload.
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 - Tải lại ứng dụng lên và cài đặt lại trong nhóm/cuộc trò chuyện
- Kiểm tra xem quản trị viên tổ chức của bạn có chặn quyền RSC không
- Xác nhận bạn đang dùng đúng phạm vi:
ChannelMessage.Read.Groupcho nhóm,ChatMessage.Read.Chatcho cuộc trò chuyện nhóm
Tài liệu tham khảo
- Tạo Azure Bot - hướng dẫn thiết lập Azure Bot
- Teams Developer Portal - tạo/quản lý ứng dụng Teams
- Lược đồ manifest ứng dụng Teams
- Nhận tin nhắn kênh bằng RSC
- Tài liệu tham khảo về quyền RSC
- Xử lý tệp của bot Teams (kênh/nhóm yêu cầu Graph)
- Nhắn tin chủ động
- @microsoft/teams.cli - Teams CLI để quản lý bot
Liên quan
- Tổng quan về kênh - tất cả các kênh được hỗ trợ
- Ghép nối - luồng xác thực và ghép nối qua DM
- Nhóm - hành vi trò chuyện nhóm và cổng mention
- Định tuyến kênh - định tuyến phiên cho tin nhắn
- Bảo mật - mô hình truy cập và gia cố