Documentation Index
Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
Use this file to discover all available pages before exploring further.
Status: teks + lampiran DM didukung; pengiriman file channel/grup memerlukan sharePointSiteId + izin Graph (lihat Mengirim file dalam obrolan grup). Poll dikirim melalui Adaptive Cards. Tindakan pesan mengekspos upload-file eksplisit untuk pengiriman yang mengutamakan file.
Plugin bawaan
Microsoft Teams dikirim sebagai Plugin bawaan dalam rilis OpenClaw saat ini, jadi tidak
diperlukan instalasi terpisah dalam build paket normal.
Jika Anda menggunakan build lama atau instalasi kustom yang mengecualikan Teams bawaan,
instal paket npm secara langsung:
openclaw plugins install @openclaw/msteams
Gunakan paket polos untuk mengikuti tag rilis resmi saat ini. Sematkan versi
persis hanya saat Anda memerlukan instalasi yang dapat direproduksi.
Checkout lokal (saat berjalan dari repo git):
openclaw plugins install ./path/to/local/msteams-plugin
Detail: Plugin
Penyiapan cepat
@microsoft/teams.cli menangani pendaftaran bot, pembuatan manifest, dan pembuatan kredensial dalam satu perintah.
1. Instal dan masuk
npm install -g @microsoft/teams.cli@preview
teams login
teams status # verify you're logged in and see your tenant info
Teams CLI saat ini dalam pratinjau. Perintah dan flag dapat berubah antar rilis.
2. Mulai tunnel (Teams tidak dapat menjangkau localhost)
Instal dan autentikasi devtunnel CLI jika Anda belum melakukannya (panduan memulai).
# 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
--allow-anonymous diperlukan karena Teams tidak dapat mengautentikasi dengan devtunnels. Setiap permintaan bot yang masuk tetap divalidasi oleh Teams SDK secara otomatis.
Alternatif: ngrok http 3978 atau tailscale funnel 3978 (tetapi ini dapat mengubah URL setiap sesi).
3. Buat aplikasi
teams app create \
--name "OpenClaw" \
--endpoint "https://<your-tunnel-url>/api/messages"
Perintah tunggal ini:
- Membuat aplikasi Entra ID (Azure AD)
- Menghasilkan client secret
- Membangun dan mengunggah manifest aplikasi Teams (dengan ikon)
- Mendaftarkan bot (dikelola Teams secara default - tidak perlu langganan Azure)
Output akan menampilkan CLIENT_ID, CLIENT_SECRET, TENANT_ID, dan Teams App ID - catat ini untuk langkah berikutnya. Output juga menawarkan untuk menginstal aplikasi di Teams secara langsung.
4. Konfigurasikan OpenClaw menggunakan kredensial dari output:
{
channels: {
msteams: {
enabled: true,
appId: "<CLIENT_ID>",
appPassword: "<CLIENT_SECRET>",
tenantId: "<TENANT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Atau gunakan variabel lingkungan secara langsung: MSTEAMS_APP_ID, MSTEAMS_APP_PASSWORD, MSTEAMS_TENANT_ID.
5. Instal aplikasi di Teams
teams app create akan meminta Anda menginstal aplikasi - pilih “Install in Teams”. Jika Anda melewatkannya, Anda dapat memperoleh tautannya nanti:
teams app get <teamsAppId> --install-link
6. Verifikasi semuanya berfungsi
teams app doctor <teamsAppId>
Ini menjalankan diagnostik di seluruh pendaftaran bot, konfigurasi aplikasi AAD, validitas manifest, dan penyiapan SSO.
Untuk deployment produksi, pertimbangkan menggunakan autentikasi terfederasi (sertifikat atau managed identity) alih-alih client secret.
Obrolan grup diblokir secara default (channels.msteams.groupPolicy: "allowlist"). Untuk mengizinkan balasan grup, tetapkan channels.msteams.groupAllowFrom, atau gunakan groupPolicy: "open" untuk mengizinkan anggota mana pun (dibatasi mention).
Tujuan
- Berbicara dengan OpenClaw melalui DM Teams, obrolan grup, atau channel.
- Menjaga routing tetap deterministik: balasan selalu kembali ke channel tempat balasan diterima.
- Secara default menggunakan perilaku channel yang aman (mention diperlukan kecuali dikonfigurasi lain).
Penulisan konfigurasi
Secara default, Microsoft Teams diizinkan menulis pembaruan konfigurasi yang dipicu oleh /config set|unset (memerlukan commands.config: true).
Nonaktifkan dengan:
{
channels: { msteams: { configWrites: false } },
}
Kontrol akses (DM + grup)
Akses DM
- Default:
channels.msteams.dmPolicy = "pairing". Pengirim tidak dikenal diabaikan hingga disetujui.
channels.msteams.allowFrom harus menggunakan ID objek AAD yang stabil atau grup akses pengirim statis seperti accessGroup:core-team.
- Jangan mengandalkan pencocokan UPN/nama tampilan untuk allowlist - keduanya dapat berubah. OpenClaw menonaktifkan pencocokan nama langsung secara default; ikut serta secara eksplisit dengan
channels.msteams.dangerouslyAllowNameMatching: true.
- Wizard dapat menyelesaikan nama menjadi ID melalui Microsoft Graph saat kredensial mengizinkan.
Akses grup
- Default:
channels.msteams.groupPolicy = "allowlist" (diblokir kecuali Anda menambahkan groupAllowFrom). Gunakan channels.defaults.groupPolicy untuk menimpa default saat belum ditetapkan.
channels.msteams.groupAllowFrom mengontrol pengirim atau grup akses pengirim statis mana yang dapat memicu dalam obrolan grup/channel (fallback ke channels.msteams.allowFrom).
- Tetapkan
groupPolicy: "open" untuk mengizinkan anggota mana pun (tetap dibatasi mention secara default).
- Untuk tidak mengizinkan channel apa pun, tetapkan
channels.msteams.groupPolicy: "disabled".
Contoh:
{
channels: {
msteams: {
groupPolicy: "allowlist",
groupAllowFrom: ["00000000-0000-0000-0000-000000000000", "accessGroup:core-team"],
},
},
}
Teams + allowlist channel
- Batasi cakupan balasan grup/channel dengan mencantumkan teams dan channel di bawah
channels.msteams.teams.
- Key harus menggunakan ID percakapan Teams yang stabil dari tautan Teams, bukan nama tampilan yang dapat berubah.
- Saat
groupPolicy="allowlist" dan allowlist teams ada, hanya teams/channel yang tercantum yang diterima (dibatasi mention).
- Wizard konfigurasi menerima entri
Team/Channel dan menyimpannya untuk Anda.
- Saat startup, OpenClaw menyelesaikan nama allowlist team/channel dan pengguna menjadi ID (saat izin Graph mengizinkan)
dan mencatat pemetaan; nama team/channel yang tidak terselesaikan disimpan sebagaimana diketik tetapi diabaikan untuk routing secara default kecuali
channels.msteams.dangerouslyAllowNameMatching: true diaktifkan.
Contoh:
{
channels: {
msteams: {
groupPolicy: "allowlist",
teams: {
"My Team": {
channels: {
General: { requireMention: true },
},
},
},
},
},
}
Autentikasi terfederasi (sertifikat plus managed identity)
Ditambahkan pada 2026.4.11
Untuk deployment produksi, OpenClaw mendukung autentikasi terfederasi sebagai alternatif yang lebih aman untuk client secret. Tersedia dua metode:
Opsi A: Autentikasi berbasis sertifikat
Gunakan sertifikat PEM yang terdaftar dengan pendaftaran aplikasi Entra ID Anda.
Penyiapan:
- Buat atau dapatkan sertifikat (format PEM dengan private key).
- Di Entra ID → App Registration → Certificates & secrets → Certificates → Unggah sertifikat publik.
Konfigurasi:
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
tenantId: "<TENANT_ID>",
authType: "federated",
certificatePath: "/path/to/cert.pem",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Variabel lingkungan:
MSTEAMS_AUTH_TYPE=federated
MSTEAMS_CERTIFICATE_PATH=/path/to/cert.pem
Opsi B: Azure Managed Identity
Gunakan Azure Managed Identity untuk autentikasi tanpa kata sandi. Ini ideal untuk deployment pada infrastruktur Azure (AKS, App Service, Azure VM) tempat managed identity tersedia.
Cara kerjanya:
- Pod/VM bot memiliki managed identity (ditetapkan sistem atau ditetapkan pengguna).
- Kredensial identitas terfederasi menautkan managed identity ke pendaftaran aplikasi Entra ID.
- Saat runtime, OpenClaw menggunakan
@azure/identity untuk memperoleh token dari endpoint Azure IMDS (169.254.169.254).
- Token diteruskan ke Teams SDK untuk autentikasi bot.
Prasyarat:
- Infrastruktur Azure dengan managed identity diaktifkan (identitas workload AKS, App Service, VM)
- Kredensial identitas terfederasi dibuat pada pendaftaran aplikasi Entra ID
- Akses jaringan ke IMDS (
169.254.169.254:80) dari pod/VM
Konfigurasi (managed identity yang ditetapkan sistem):
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
tenantId: "<TENANT_ID>",
authType: "federated",
useManagedIdentity: true,
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Konfigurasi (managed identity yang ditetapkan pengguna):
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
tenantId: "<TENANT_ID>",
authType: "federated",
useManagedIdentity: true,
managedIdentityClientId: "<MI_CLIENT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Variabel lingkungan:
MSTEAMS_AUTH_TYPE=federated
MSTEAMS_USE_MANAGED_IDENTITY=true
MSTEAMS_MANAGED_IDENTITY_CLIENT_ID=<client-id> (hanya untuk yang ditetapkan pengguna)
Penyiapan AKS Workload Identity
Untuk deployment AKS yang menggunakan workload identity:
-
Aktifkan workload identity pada kluster AKS Anda.
-
Buat kredensial identitas federasi pada pendaftaran aplikasi 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"]
}'
-
Anotasikan akun layanan Kubernetes dengan ID klien aplikasi:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-bot-sa
annotations:
azure.workload.identity/client-id: "<APP_CLIENT_ID>"
-
Beri label pada pod untuk injeksi workload identity:
metadata:
labels:
azure.workload.identity/use: "true"
-
Pastikan akses jaringan ke IMDS (
169.254.169.254) - jika menggunakan NetworkPolicy, tambahkan aturan egress yang mengizinkan lalu lintas ke 169.254.169.254/32 pada port 80.
Perbandingan jenis autentikasi
| Metode | Konfigurasi | Kelebihan | Kekurangan |
|---|
| Rahasia klien | appPassword | Penyiapan sederhana | Rotasi rahasia diperlukan, kurang aman |
| Sertifikat | authType: "federated" + certificatePath | Tidak ada rahasia bersama melalui jaringan | Beban pengelolaan sertifikat |
| Managed Identity | authType: "federated" + useManagedIdentity | Tanpa kata sandi, tidak ada rahasia untuk dikelola | Infrastruktur Azure diperlukan |
Perilaku default: Saat authType tidak diatur, OpenClaw menggunakan autentikasi rahasia klien secara default. Konfigurasi yang sudah ada tetap berfungsi tanpa perubahan.
Pengembangan lokal (tunneling)
Teams tidak dapat menjangkau localhost. Gunakan tunnel pengembangan persisten agar URL Anda tetap sama di seluruh sesi:
# 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
Alternatif: ngrok http 3978 atau tailscale funnel 3978 (URL dapat berubah pada setiap sesi).
Jika URL tunnel Anda berubah, perbarui endpoint:
teams app update <teamsAppId> --endpoint "https://<new-url>/api/messages"
Menguji Bot
Jalankan diagnostik:
teams app doctor <teamsAppId>
Memeriksa pendaftaran bot, aplikasi AAD, manifes, dan konfigurasi SSO dalam satu lintasan.
Kirim pesan uji:
- Instal aplikasi Teams (gunakan tautan instal dari
teams app get <id> --install-link)
- Temukan bot di Teams dan kirim DM
- Periksa log Gateway untuk aktivitas masuk
Variabel lingkungan
Semua kunci konfigurasi dapat diatur melalui variabel lingkungan sebagai gantinya:
MSTEAMS_APP_ID
MSTEAMS_APP_PASSWORD
MSTEAMS_TENANT_ID
MSTEAMS_AUTH_TYPE (opsional: "secret" atau "federated")
MSTEAMS_CERTIFICATE_PATH (federated + sertifikat)
MSTEAMS_CERTIFICATE_THUMBPRINT (opsional, tidak diperlukan untuk autentikasi)
MSTEAMS_USE_MANAGED_IDENTITY (federated + managed identity)
MSTEAMS_MANAGED_IDENTITY_CLIENT_ID (hanya MI yang ditetapkan pengguna)
Tindakan info anggota
OpenClaw mengekspos tindakan member-info yang didukung Graph untuk Microsoft Teams agar agent dan automasi dapat me-resolve detail anggota channel (nama tampilan, email, peran) langsung dari Microsoft Graph.
Persyaratan:
- Izin RSC
Member.Read.Group (sudah ada dalam manifes yang direkomendasikan)
- Untuk lookup lintas tim: izin Graph Application
User.Read.All dengan persetujuan admin
Tindakan ini dikendalikan oleh channels.msteams.actions.memberInfo (default: aktif saat kredensial Graph tersedia).
Konteks riwayat
channels.msteams.historyLimit mengontrol berapa banyak pesan channel/grup terbaru yang dibungkus ke dalam prompt.
- Fallback ke
messages.groupChat.historyLimit. Atur 0 untuk menonaktifkan (default 50).
- Riwayat thread yang diambil difilter berdasarkan daftar izin pengirim (
allowFrom / groupAllowFrom), sehingga penyemaian konteks thread hanya menyertakan pesan dari pengirim yang diizinkan.
- Konteks lampiran yang dikutip (
ReplyTo* yang diturunkan dari HTML balasan Teams) saat ini diteruskan sebagaimana diterima.
- Dengan kata lain, daftar izin mengatur siapa yang dapat memicu agent; hanya jalur konteks tambahan tertentu yang difilter saat ini.
- Riwayat DM dapat dibatasi dengan
channels.msteams.dmHistoryLimit (giliran pengguna). Override per pengguna: channels.msteams.dms["<user_id>"].historyLimit.
Izin RSC Teams saat ini (manifes)
Berikut adalah izin resourceSpecific yang ada dalam manifes aplikasi Teams kami. Izin ini hanya berlaku di dalam tim/chat tempat aplikasi diinstal.
Untuk channel (cakupan tim):
ChannelMessage.Read.Group (Application) - menerima semua pesan channel tanpa @mention
ChannelMessage.Send.Group (Application)
Member.Read.Group (Application)
Owner.Read.Group (Application)
ChannelSettings.Read.Group (Application)
TeamMember.Read.Group (Application)
TeamSettings.Read.Group (Application)
Untuk chat grup:
ChatMessage.Read.Chat (Application) - menerima semua pesan chat grup tanpa @mention
Untuk menambahkan izin RSC melalui Teams CLI:
teams app rsc add <teamsAppId> ChannelMessage.Read.Group --type Application
Contoh manifes Teams (disunting)
Contoh minimal dan valid dengan kolom yang diperlukan. Ganti ID dan 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" },
],
},
},
}
Catatan manifes (kolom wajib)
bots[].botId harus cocok dengan ID Aplikasi Azure Bot.
webApplicationInfo.id harus cocok dengan ID Aplikasi Azure Bot.
bots[].scopes harus menyertakan permukaan yang Anda rencanakan untuk digunakan (personal, team, groupChat).
bots[].supportsFiles: true diperlukan untuk penanganan file dalam cakupan personal.
authorization.permissions.resourceSpecific harus menyertakan baca/kirim channel jika Anda menginginkan lalu lintas channel.
Memperbarui aplikasi yang ada
Untuk memperbarui aplikasi Teams yang sudah terinstal (misalnya, untuk menambahkan izin 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
Setelah memperbarui, instal ulang aplikasi di setiap tim agar izin baru berlaku, dan keluar sepenuhnya lalu luncurkan ulang Teams (bukan hanya menutup jendela) untuk menghapus metadata aplikasi yang di-cache.
Kemampuan: hanya RSC vs Graph
Dengan hanya Teams RSC (aplikasi terinstal, tanpa izin Graph API)
Berfungsi:
- Membaca konten teks pesan channel.
- Mengirim konten teks pesan channel.
- Menerima lampiran file personal (DM).
TIDAK berfungsi:
- Isi gambar atau file channel/grup (payload hanya menyertakan stub HTML).
- Mengunduh lampiran yang disimpan di SharePoint/OneDrive.
- Membaca riwayat pesan (di luar event Webhook langsung).
Dengan Teams RSC + izin Microsoft Graph Application
Menambahkan:
- Mengunduh konten yang di-host (gambar yang ditempelkan ke pesan).
- Mengunduh lampiran file yang disimpan di SharePoint/OneDrive.
- Membaca riwayat pesan channel/chat melalui Graph.
RSC vs Graph API
| Kemampuan | Izin RSC | Graph API |
|---|
| Pesan real-time | Ya (melalui Webhook) | Tidak (hanya polling) |
| Pesan historis | Tidak | Ya (dapat mengueri riwayat) |
| Kompleksitas penyiapan | Hanya manifes aplikasi | Memerlukan persetujuan admin + alur token |
| Berfungsi offline | Tidak (harus berjalan) | Ya (kueri kapan saja) |
Intinya: RSC untuk mendengarkan secara real-time; Graph API untuk akses historis. Untuk mengejar pesan yang terlewat saat offline, Anda memerlukan Graph API dengan ChannelMessage.Read.All (memerlukan persetujuan admin).
Jika Anda memerlukan gambar/file di channel atau ingin mengambil riwayat pesan, Anda harus mengaktifkan izin Microsoft Graph dan memberikan persetujuan admin.
- Di Entra ID (Azure AD) App Registration, tambahkan izin Application Microsoft Graph:
ChannelMessage.Read.All (lampiran channel + riwayat)
Chat.Read.All atau ChatMessage.Read.All (chat grup)
- Berikan persetujuan admin untuk tenant.
- Naikkan versi manifes aplikasi Teams, unggah ulang, dan instal ulang aplikasi di Teams.
- Keluar sepenuhnya lalu luncurkan ulang Teams untuk menghapus metadata aplikasi yang di-cache.
Izin tambahan untuk mention pengguna: @mention pengguna berfungsi langsung untuk pengguna dalam percakapan. Namun, jika Anda ingin mencari dan me-mention pengguna secara dinamis yang tidak berada dalam percakapan saat ini, tambahkan izin User.Read.All (Application) dan berikan persetujuan admin.
Batasan yang diketahui
Timeout Webhook
Teams mengirimkan pesan melalui Webhook HTTP. Jika pemrosesan terlalu lama (misalnya, respons LLM yang lambat), Anda mungkin melihat:
- Timeout Gateway
- Teams mencoba ulang pesan (menyebabkan duplikasi)
- Balasan yang terlewat
OpenClaw menangani ini dengan kembali secara cepat dan mengirim balasan secara proaktif, tetapi respons yang sangat lambat masih dapat menyebabkan masalah.
Markdown Teams lebih terbatas daripada Slack atau Discord:
- Pemformatan dasar berfungsi: tebal, miring,
code, tautan
- Markdown kompleks (tabel, daftar bertingkat) mungkin tidak dirender dengan benar
- Adaptive Cards didukung untuk jajak pendapat dan pengiriman presentasi semantik (lihat di bawah)
Konfigurasi
Pengaturan utama (lihat /gateway/configuration untuk pola channel bersama):
channels.msteams.enabled: aktifkan/nonaktifkan channel.
channels.msteams.appId, channels.msteams.appPassword, channels.msteams.tenantId: kredensial bot.
channels.msteams.webhook.port (default 3978)
channels.msteams.webhook.path (default /api/messages)
channels.msteams.dmPolicy: pairing | allowlist | open | disabled (default: pairing)
channels.msteams.allowFrom: daftar yang diizinkan untuk DM (ID objek AAD direkomendasikan). Wizard menyelesaikan nama menjadi ID saat penyiapan ketika akses Graph tersedia.
channels.msteams.dangerouslyAllowNameMatching: toggle darurat untuk mengaktifkan kembali pencocokan UPN/nama tampilan yang dapat berubah dan perutean nama tim/channel langsung.
channels.msteams.textChunkLimit: ukuran potongan teks keluar.
channels.msteams.chunkMode: length (default) atau newline untuk memisahkan pada baris kosong (batas paragraf) sebelum pemotongan berdasarkan panjang.
channels.msteams.mediaAllowHosts: daftar host yang diizinkan untuk lampiran masuk (default ke domain Microsoft/Teams).
channels.msteams.mediaAuthAllowHosts: daftar host yang diizinkan untuk melampirkan header Authorization pada percobaan ulang media (default ke host Graph + Bot Framework).
channels.msteams.requireMention: wajibkan @mention di channel/grup (default true).
channels.msteams.replyStyle: thread | top-level (lihat Gaya Balasan).
channels.msteams.teams.<teamId>.replyStyle: override per tim.
channels.msteams.teams.<teamId>.requireMention: override per tim.
channels.msteams.teams.<teamId>.tools: override kebijakan tool default per tim (allow/deny/alsoAllow) yang digunakan saat override channel tidak ada.
channels.msteams.teams.<teamId>.toolsBySender: override kebijakan tool default per tim per pengirim ("*" wildcard didukung).
channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle: override per channel.
channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention: override per channel.
channels.msteams.teams.<teamId>.channels.<conversationId>.tools: override kebijakan tool per channel (allow/deny/alsoAllow).
channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender: override kebijakan tool per channel per pengirim ("*" wildcard didukung).
- Kunci
toolsBySender sebaiknya menggunakan prefiks eksplisit:
channel:, id:, e164:, username:, name: (kunci lama tanpa prefiks masih hanya dipetakan ke id:).
channels.msteams.actions.memberInfo: aktifkan atau nonaktifkan aksi info anggota yang didukung Graph (default: diaktifkan ketika kredensial Graph tersedia).
channels.msteams.authType: jenis autentikasi - "secret" (default) atau "federated".
channels.msteams.certificatePath: path ke file sertifikat PEM (federated + autentikasi sertifikat).
channels.msteams.certificateThumbprint: thumbprint sertifikat (opsional, tidak diperlukan untuk autentikasi).
channels.msteams.useManagedIdentity: aktifkan autentikasi managed identity (mode federated).
channels.msteams.managedIdentityClientId: ID klien untuk managed identity yang ditetapkan pengguna.
channels.msteams.sharePointSiteId: ID situs SharePoint untuk unggahan file dalam obrolan grup/channel (lihat Mengirim file dalam obrolan grup).
Perutean dan sesi
- Kunci sesi mengikuti format agen standar (lihat /concepts/session):
- Pesan langsung berbagi sesi utama (
agent:<agentId>:<mainKey>).
- Pesan channel/grup menggunakan ID percakapan:
agent:<agentId>:msteams:channel:<conversationId>
agent:<agentId>:msteams:group:<conversationId>
Gaya balasan: thread vs postingan
Teams baru-baru ini memperkenalkan dua gaya UI channel di atas model data dasar yang sama:
| Gaya | Deskripsi | replyStyle yang direkomendasikan |
|---|
| Postingan (klasik) | Pesan muncul sebagai kartu dengan balasan ber-thread di bawahnya | thread (default) |
| Thread (mirip Slack) | Pesan mengalir secara linear, lebih mirip Slack | top-level |
Masalahnya: API Teams tidak mengekspos gaya UI mana yang digunakan channel. Jika Anda menggunakan replyStyle yang salah:
thread di channel bergaya Thread → balasan muncul bertingkat dengan canggung
top-level di channel bergaya Postingan → balasan muncul sebagai postingan tingkat atas terpisah, bukan di dalam thread
Solusi: Konfigurasikan replyStyle per channel berdasarkan bagaimana channel disiapkan:
{
channels: {
msteams: {
replyStyle: "thread",
teams: {
"19:abc...@thread.tacv2": {
channels: {
"19:xyz...@thread.tacv2": {
replyStyle: "top-level",
},
},
},
},
},
},
}
Prioritas resolusi
Ketika bot mengirim balasan ke channel, replyStyle diselesaikan dari override yang paling spesifik hingga default. Nilai pertama yang bukan undefined yang menang:
- Per channel —
channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle
- Per tim —
channels.msteams.teams.<teamId>.replyStyle
- Global —
channels.msteams.replyStyle
- Default implisit — diturunkan dari
requireMention:
requireMention: true → thread
requireMention: false → top-level
Jika Anda menetapkan requireMention: false secara global tanpa replyStyle eksplisit, mention di channel bergaya Postingan akan muncul sebagai postingan tingkat atas meskipun pesan masuknya adalah balasan thread. Pin replyStyle: "thread" pada tingkat global, tim, atau channel untuk menghindari kejutan.
Pelestarian konteks thread
Ketika replyStyle: "thread" berlaku dan bot di-@mention dari dalam thread channel, OpenClaw melampirkan kembali root thread asli ke referensi percakapan keluar (19:…@thread.tacv2;messageid=<root>) agar balasan masuk ke thread yang sama. Ini berlaku untuk pengiriman live (dalam turn) maupun pengiriman proaktif yang dibuat setelah konteks turn Bot Framework kedaluwarsa (misalnya, agen yang berjalan lama, balasan tool-call antrean melalui mcp__openclaw__message).
Root thread diambil dari threadId yang disimpan pada referensi percakapan. Referensi tersimpan lama yang dibuat sebelum threadId kembali menggunakan activityId (aktivitas masuk apa pun yang terakhir menanam percakapan), sehingga deployment yang ada tetap berfungsi tanpa seeding ulang.
Ketika replyStyle: "top-level" berlaku, pesan masuk thread channel sengaja dijawab sebagai postingan tingkat atas baru — tidak ada sufiks thread yang dilampirkan. Ini adalah perilaku yang benar untuk channel bergaya Thread; jika Anda melihat postingan tingkat atas ketika mengharapkan balasan ber-thread, replyStyle Anda diatur secara keliru untuk channel tersebut.
Lampiran dan gambar
Batasan saat ini:
- DM: Gambar dan lampiran file berfungsi melalui API file bot Teams.
- Channel/grup: Lampiran berada di penyimpanan M365 (SharePoint/OneDrive). Payload Webhook hanya menyertakan stub HTML, bukan byte file aktual. Izin Graph API diperlukan untuk mengunduh lampiran channel.
- Untuk pengiriman eksplisit yang mendahulukan file, gunakan
action=upload-file dengan media / filePath / path; message opsional menjadi teks/komentar pendamping, dan filename mengganti nama unggahan.
Tanpa izin Graph, pesan channel dengan gambar akan diterima sebagai teks saja (konten gambar tidak dapat diakses oleh bot).
Secara default, OpenClaw hanya mengunduh media dari hostname Microsoft/Teams. Override dengan channels.msteams.mediaAllowHosts (gunakan ["*"] untuk mengizinkan host apa pun).
Header Authorization hanya dilampirkan untuk host dalam channels.msteams.mediaAuthAllowHosts (default ke host Graph + Bot Framework). Jaga daftar ini tetap ketat (hindari sufiks multi-tenant).
Mengirim file dalam obrolan grup
Bot dapat mengirim file dalam DM menggunakan alur FileConsentCard (bawaan). Namun, mengirim file dalam obrolan grup/channel memerlukan penyiapan tambahan:
| Konteks | Cara file dikirim | Penyiapan yang diperlukan |
|---|
| DM | FileConsentCard → pengguna menerima → bot mengunggah | Berfungsi langsung tanpa konfigurasi tambahan |
| Obrolan grup/channel | Unggah ke SharePoint → bagikan tautan | Memerlukan sharePointSiteId + izin Graph |
| Gambar (konteks apa pun) | Inline berenkode Base64 | Berfungsi langsung tanpa konfigurasi tambahan |
Mengapa obrolan grup memerlukan SharePoint
Bot tidak memiliki drive OneDrive pribadi (endpoint Graph API /me/drive tidak berfungsi untuk identitas aplikasi). Untuk mengirim file dalam obrolan grup/channel, bot mengunggah ke situs SharePoint dan membuat tautan berbagi.
Penyiapan
-
Tambahkan izin Graph API di Entra ID (Azure AD) → App Registration:
Sites.ReadWrite.All (Application) - mengunggah file ke SharePoint
Chat.Read.All (Application) - opsional, mengaktifkan tautan berbagi per pengguna
-
Berikan persetujuan admin untuk tenant.
-
Dapatkan ID situs SharePoint Anda:
# 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"
-
Konfigurasikan OpenClaw:
{
channels: {
msteams: {
// ... other config ...
sharePointSiteId: "contoso.sharepoint.com,guid1,guid2",
},
},
}
Perilaku berbagi
| Izin | Perilaku berbagi |
|---|
Sites.ReadWrite.All saja | Tautan berbagi seluruh organisasi (siapa pun di org dapat mengakses) |
Sites.ReadWrite.All + Chat.Read.All | Tautan berbagi per pengguna (hanya anggota chat yang dapat mengakses) |
Berbagi per pengguna lebih aman karena hanya peserta chat yang dapat mengakses file. Jika izin Chat.Read.All tidak ada, bot kembali menggunakan berbagi seluruh organisasi.
Perilaku fallback
| Skenario | Hasil |
|---|
Obrolan grup + file + sharePointSiteId dikonfigurasi | Unggah ke SharePoint, kirim tautan berbagi |
Obrolan grup + file + tanpa sharePointSiteId | Coba unggah OneDrive (mungkin gagal), kirim teks saja |
| Chat pribadi + file | Alur FileConsentCard (berfungsi tanpa SharePoint) |
| Konteks apa pun + gambar | Inline berenkode Base64 (berfungsi tanpa SharePoint) |
Lokasi file tersimpan
File yang diunggah disimpan dalam folder /OpenClawShared/ di pustaka dokumen default situs SharePoint yang dikonfigurasi.
Jajak pendapat (Adaptive Cards)
OpenClaw mengirim jajak pendapat Teams sebagai Adaptive Cards (tidak ada API jajak pendapat Teams native).
- CLI:
openclaw message poll --channel msteams --target conversation:<id> ...
- Suara dicatat oleh Gateway di
~/.openclaw/msteams-polls.json.
- Gateway harus tetap online untuk mencatat suara.
- Polling belum memposting ringkasan hasil secara otomatis (periksa file store jika diperlukan).
Kartu presentasi
Kirim payload presentasi semantik ke pengguna atau percakapan Teams menggunakan alat message atau CLI. OpenClaw merendernya sebagai Teams Adaptive Cards dari kontrak presentasi generik.
Parameter presentation menerima blok semantik. Ketika presentation disediakan, teks pesan bersifat opsional.
Alat agen:
{
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!"}]}'
Untuk detail format target, lihat Format target di bawah.
Target MSTeams menggunakan prefiks untuk membedakan pengguna dan percakapan:
| Jenis target | Format | Contoh |
|---|
| Pengguna (berdasarkan ID) | user:<aad-object-id> | user:40a1a0ed-4ff2-4164-a219-55518990c197 |
| Pengguna (berdasarkan nama) | user:<display-name> | user:John Smith (memerlukan Graph API) |
| Grup/channel | conversation:<conversation-id> | conversation:19:abc123...@thread.tacv2 |
| Grup/channel (mentah) | <conversation-id> | 19:abc123...@thread.tacv2 (jika berisi @thread) |
Contoh 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:abc...@thread.tacv2" --message "Hello"
# Send a presentation card to a conversation
openclaw message send --channel msteams --target "conversation:19:abc...@thread.tacv2" \
--presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello"}]}'
Contoh alat agen:
{
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" }],
},
}
Tanpa prefiks user:, nama secara default diselesaikan sebagai grup atau tim. Selalu gunakan user: saat menargetkan orang berdasarkan nama tampilan.
Pesan proaktif
- Pesan proaktif hanya mungkin setelah pengguna berinteraksi, karena kami menyimpan referensi percakapan pada titik tersebut.
- Lihat
/gateway/configuration untuk dmPolicy dan gating allowlist.
ID Tim dan Channel (Jebakan Umum)
Parameter kueri groupId dalam URL Teams BUKAN ID tim yang digunakan untuk konfigurasi. Ekstrak ID dari path URL sebagai gantinya:
URL Tim:
https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
└────────────────────────────┘
Team conversation ID (URL-decode this)
URL Channel:
https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
└─────────────────────────┘
Channel ID (URL-decode this)
Untuk konfigurasi:
- Kunci tim = segmen path setelah
/team/ (di-URL-decode, misalnya, 19:Bk4j...@thread.tacv2; tenant lama mungkin menampilkan @thread.skype, yang juga valid)
- Kunci channel = segmen path setelah
/channel/ (di-URL-decode)
- Abaikan parameter kueri
groupId untuk routing OpenClaw. Itu adalah ID grup Microsoft Entra, bukan ID percakapan Bot Framework yang digunakan dalam aktivitas Teams yang masuk.
Channel privat
Bot memiliki dukungan terbatas di channel privat:
| Fitur | Channel Standar | Channel Privat |
|---|
| Instalasi bot | Ya | Terbatas |
| Pesan real-time (webhook) | Ya | Mungkin tidak berfungsi |
| Izin RSC | Ya | Mungkin berperilaku berbeda |
| @mention | Ya | Jika bot dapat diakses |
| Riwayat Graph API | Ya | Ya (dengan izin) |
Solusi sementara jika channel privat tidak berfungsi:
- Gunakan channel standar untuk interaksi bot
- Gunakan DM - pengguna selalu dapat mengirim pesan langsung ke bot
- Gunakan Graph API untuk akses historis (memerlukan
ChannelMessage.Read.All)
Pemecahan masalah
Masalah umum
- Gambar tidak muncul di channel: Izin Graph atau persetujuan admin hilang. Instal ulang aplikasi Teams dan tutup sepenuhnya/buka kembali Teams.
- Tidak ada respons di channel: mention diperlukan secara default; atur
channels.msteams.requireMention=false atau konfigurasikan per tim/channel.
- Ketidakcocokan versi (Teams masih menampilkan manifes lama): hapus + tambahkan ulang aplikasi dan tutup Teams sepenuhnya untuk menyegarkan.
- 401 Unauthorized dari webhook: Diharapkan saat menguji secara manual tanpa Azure JWT - berarti endpoint dapat dijangkau tetapi autentikasi gagal. Gunakan Azure Web Chat untuk menguji dengan benar.
Kesalahan unggah manifes
- “Icon file cannot be empty”: Manifes merujuk file ikon yang berukuran 0 byte. Buat ikon PNG yang valid (32x32 untuk
outline.png, 192x192 untuk color.png).
- “webApplicationInfo.Id already in use”: Aplikasi masih terpasang di tim/chat lain. Temukan dan copot pemasangannya terlebih dahulu, atau tunggu 5-10 menit untuk propagasi.
- “Something went wrong” saat mengunggah: Unggah melalui https://admin.teams.microsoft.com sebagai gantinya, buka DevTools browser (F12) → tab Network, dan periksa body respons untuk kesalahan sebenarnya.
- Sideload gagal: Coba “Upload an app to your org’s app catalog” alih-alih “Upload a custom app” - ini sering melewati pembatasan sideload.
Izin RSC tidak berfungsi
- Verifikasi
webApplicationInfo.id sama persis dengan App ID bot Anda
- Unggah ulang aplikasi dan instal ulang di tim/chat
- Periksa apakah admin organisasi Anda telah memblokir izin RSC
- Konfirmasi Anda menggunakan scope yang tepat:
ChannelMessage.Read.Group untuk tim, ChatMessage.Read.Chat untuk chat grup
Referensi
Terkait