Microsoft Teams (plugin)
“Abandon all hope, ye who enter here.”
Atualizado: 2026-01-21
Status: texto + anexos em DM são suportados; envio de arquivos em canais/grupos requer sharePointSiteId + permissões do Graph (veja Envio de arquivos em chats de grupo). Enquetes são enviadas via Adaptive Cards.
Plugin necessário
O Microsoft Teams é distribuído como plugin e não vem incluído na instalação principal.
Mudança incompatível (2026.1.15): MS Teams foi removido do core. Se você o utiliza, precisa instalar o plugin.
Justificativa: mantém a instalação core mais leve e permite que as dependências do MS Teams sejam atualizadas independentemente.
Instale via CLI (registro npm):
openclaw plugins install @openclaw/msteams
Checkout local (ao executar de um repositório git):
openclaw plugins install ./extensions/msteams
Se você escolher o Teams durante a configuração/onboarding e um checkout git for detectado, o OpenClaw oferecerá o caminho de instalação local automaticamente.
Detalhes: Plugins
Configuração rápida (iniciante)
- Instale o plugin do Microsoft Teams.
- Crie um Azure Bot (App ID + client secret + tenant ID).
- Configure o OpenClaw com essas credenciais.
- Exponha
/api/messages(porta 3978 por padrão) via URL pública ou túnel. - Instale o pacote do app Teams e inicie o gateway.
Configuração mínima:
{
channels: {
msteams: {
enabled: true,
appId: "<APP_ID>",
appPassword: "<APP_PASSWORD>",
tenantId: "<TENANT_ID>",
webhook: { port: 3978, path: "/api/messages" },
},
},
}
Observação: chats de grupo são bloqueados por padrão (channels.msteams.groupPolicy: "allowlist"). Para permitir respostas em grupo, defina channels.msteams.groupAllowFrom (ou use groupPolicy: "open" para permitir qualquer membro, com filtragem por menção).
Objetivos
- Conversar com o OpenClaw via DMs, chats de grupo ou canais do Teams.
- Manter o roteamento determinístico: respostas sempre voltam para o canal de onde vieram.
- Ter comportamento de canal seguro por padrão (menções obrigatórias, a menos que configurado de outra forma).
Escritas de configuração
Por padrão, o Microsoft Teams pode escrever atualizações de configuração acionadas por /config set|unset (requer commands.config: true).
Desativar com:
{
channels: { msteams: { configWrites: false } },
}
Controle de acesso (DMs + grupos)
Acesso a DMs
- Padrão:
channels.msteams.dmPolicy = "pairing". Remetentes desconhecidos são ignorados até serem aprovados. channels.msteams.allowFromdeve usar IDs de objeto AAD estáveis.- UPNs/nomes de exibição são mutáveis; correspondência direta é desativada por padrão e só é ativada com
channels.msteams.dangerouslyAllowNameMatching: true. - O assistente pode resolver nomes para IDs via Microsoft Graph quando as credenciais permitem.
Acesso a grupos
- Padrão:
channels.msteams.groupPolicy = "allowlist"(bloqueado a menos que você adicionegroupAllowFrom). Usechannels.defaults.groupPolicypara sobrescrever o padrão quando não definido. channels.msteams.groupAllowFromcontrola quais remetentes podem acionar em chats de grupo/canais (recorre achannels.msteams.allowFrom).- Defina
groupPolicy: "open"para permitir qualquer membro (ainda com filtragem por menção por padrão). - Para não permitir nenhum canal, defina
channels.msteams.groupPolicy: "disabled".
Exemplo:
{
channels: {
msteams: {
groupPolicy: "allowlist",
groupAllowFrom: ["[email protected]"],
},
},
}
Lista de permitidos de teams + canais
- Restrinja respostas de grupo/canal listando teams e canais em
channels.msteams.teams. - As chaves devem usar IDs estáveis de team e IDs de conversa de canal.
- Quando
groupPolicy="allowlist"e uma lista de permitidos de teams está presente, apenas teams/canais listados são aceitos (com filtragem por menção). - O assistente de configuração aceita entradas
Team/Channele as armazena para você. - Na inicialização, o OpenClaw resolve nomes de team/canal e da lista de permitidos de usuários para IDs (quando as permissões do Graph permitem)
e registra o mapeamento; nomes de team/canal não resolvidos são mantidos como digitados mas ignorados para roteamento por padrão, a menos que
channels.msteams.dangerouslyAllowNameMatching: trueesteja ativado.
Exemplo:
{
channels: {
msteams: {
groupPolicy: "allowlist",
teams: {
"My Team": {
channels: {
General: { requireMention: true },
},
},
},
},
},
}
Como funciona
- Instale o plugin do Microsoft Teams.
- Crie um Azure Bot (App ID + secret + tenant ID).
- Construa um pacote de app Teams que referencia o bot e inclui as permissões RSC abaixo.
- Faça upload/instale o app Teams em um team (ou escopo pessoal para DMs).
- Configure
msteamsem~/.openclaw/openclaw.json(ou variáveis de ambiente) e inicie o gateway. - O gateway escuta tráfego de webhook do Bot Framework em
/api/messagespor padrão.
Configuração do Azure Bot (Pré-requisitos)
Antes de configurar o OpenClaw, você precisa criar um recurso Azure Bot.
Passo 1: Crie o Azure Bot
-
Acesse Criar Azure Bot
-
Preencha a aba Basics:
Campo Valor Bot handle Nome do bot, ex.: openclaw-msteams(deve ser único)Subscription Selecione sua assinatura Azure Resource group Crie novo ou use existente Pricing tier Free para dev/teste Type of App Single Tenant (recomendado - veja nota abaixo) Creation type Create new Microsoft App ID
Aviso de descontinuação: A criação de novos bots multi-tenant foi descontinuada após 2025-07-31. Use Single Tenant para novos bots.
- Clique em Review + create → Create (aguarde ~1-2 minutos)
Passo 2: Obtenha as credenciais
- Vá ao recurso Azure Bot → Configuration
- Copie Microsoft App ID → este é o seu
appId - Clique em Manage Password → vá para o App Registration
- Em Certificates & secrets → New client secret → copie o Value → este é o seu
appPassword - Vá em Overview → copie Directory (tenant) ID → este é o seu
tenantId
Passo 3: Configure o Messaging Endpoint
- No Azure Bot → Configuration
- Defina o Messaging endpoint com a URL do webhook:
- Produção:
https://your-domain.com/api/messages - Dev local: use um túnel (veja Desenvolvimento Local abaixo)
- Produção:
Passo 4: Ative o Canal Teams
- No Azure Bot → Channels
- Clique em Microsoft Teams → Configure → Save
- Aceite os Termos de Serviço
Desenvolvimento Local (Tunelamento)
O Teams não consegue acessar localhost. Use um túnel para desenvolvimento local:
Opção A: ngrok
ngrok http 3978
# Copie a URL https, ex.: https://abc123.ngrok.io
# Defina o messaging endpoint como: https://abc123.ngrok.io/api/messages
Opção B: Tailscale Funnel
tailscale funnel 3978
# Use sua URL do Tailscale Funnel como messaging endpoint
Portal de Desenvolvedores do Teams (Alternativa)
Em vez de criar manualmente um ZIP de manifesto, você pode usar o Portal de Desenvolvedores do Teams:
- Clique em + New app
- Preencha as informações básicas (nome, descrição, informações do desenvolvedor)
- Vá em App features → Bot
- Selecione Enter a bot ID manually e cole o App ID do Azure Bot
- Marque os escopos: Personal, Team, Group Chat
- Clique em Distribute → Download app package
- No Teams: Apps → Manage your apps → Upload a custom app → selecione o ZIP
Isso geralmente é mais fácil do que editar manifestos JSON manualmente.
Testando o bot
Opção A: Azure Web Chat (verifique o webhook primeiro)
- No Portal Azure → recurso Azure Bot → Test in Web Chat
- Envie uma mensagem - você deve ver uma resposta
- Isso confirma que o endpoint do webhook funciona antes da configuração do Teams
Opção B: Teams (após instalação do app)
- Instale o app Teams (sideload ou catálogo da organização)
- Encontre o bot no Teams e envie uma DM
- Verifique os logs do gateway para atividade recebida
Configuração (texto mínimo)
-
Instale o plugin do Microsoft Teams
- Via npm:
openclaw plugins install @openclaw/msteams - Via checkout local:
openclaw plugins install ./extensions/msteams
- Via npm:
-
Registro do bot
- Crie um Azure Bot (veja acima) e anote:
- App ID
- Client secret (App password)
- Tenant ID (single-tenant)
- Crie um Azure Bot (veja acima) e anote:
-
Manifesto do app Teams
- Inclua uma entrada
botcombotId = <App ID>. - Escopos:
personal,team,groupChat. supportsFiles: true(obrigatório para tratamento de arquivos no escopo pessoal).- Adicione permissões RSC (abaixo).
- Crie ícones:
outline.png(32x32) ecolor.png(192x192). - Compacte os três arquivos juntos:
manifest.json,outline.png,color.png.
- Inclua uma entrada
-
Configure o OpenClaw
{ "msteams": { "enabled": true, "appId": "<APP_ID>", "appPassword": "<APP_PASSWORD>", "tenantId": "<TENANT_ID>", "webhook": { "port": 3978, "path": "/api/messages" } } }Você também pode usar variáveis de ambiente em vez de chaves de configuração:
MSTEAMS_APP_IDMSTEAMS_APP_PASSWORDMSTEAMS_TENANT_ID
-
Endpoint do bot
- Defina o Messaging Endpoint do Azure Bot como:
https://<host>:3978/api/messages(ou o caminho/porta escolhidos).
- Defina o Messaging Endpoint do Azure Bot como:
-
Execute o gateway
- O canal Teams inicia automaticamente quando o plugin está instalado e a configuração
msteamsexiste com credenciais.
- O canal Teams inicia automaticamente quando o plugin está instalado e a configuração
Contexto de histórico
channels.msteams.historyLimitcontrola quantas mensagens recentes de canal/grupo são incluídas no prompt.- Recorre a
messages.groupChat.historyLimit. Defina0para desativar (padrão 50). - O histórico de DM pode ser limitado com
channels.msteams.dmHistoryLimit(turnos do usuário). Overrides por usuário:channels.msteams.dms["<user_id>"].historyLimit.
Permissões RSC atuais do Teams (Manifesto)
Estas são as permissões resourceSpecific existentes no manifesto do app Teams. Elas se aplicam apenas dentro do team/chat onde o app está instalado.
Para canais (escopo de team):
ChannelMessage.Read.Group(Application) - receber todas as mensagens do canal sem @mençãoChannelMessage.Send.Group(Application)Member.Read.Group(Application)Owner.Read.Group(Application)ChannelSettings.Read.Group(Application)TeamMember.Read.Group(Application)TeamSettings.Read.Group(Application)
Para chats de grupo:
ChatMessage.Read.Chat(Application) - receber todas as mensagens de chat de grupo sem @menção
Exemplo de manifesto Teams (reduzido)
Exemplo mínimo e válido com os campos obrigatórios. Substitua IDs e URLs.
{
"$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" }
]
}
}
}
Ressalvas do manifesto (campos obrigatórios)
bots[].botIddeve corresponder ao App ID do Azure Bot.webApplicationInfo.iddeve corresponder ao App ID do Azure Bot.bots[].scopesdeve incluir as superfícies que você planeja usar (personal,team,groupChat).bots[].supportsFiles: trueé obrigatório para tratamento de arquivos no escopo pessoal.authorization.permissions.resourceSpecificdeve incluir leitura/envio de canal se quiser tráfego de canal.
Atualizando um app existente
Para atualizar um app Teams já instalado (ex.: para adicionar permissões RSC):
- Atualize o
manifest.jsoncom as novas configurações - Incremente o campo
version(ex.:1.0.0→1.1.0) - Re-compacte o manifesto com ícones (
manifest.json,outline.png,color.png) - Faça upload do novo zip:
- Opção A (Teams Admin Center): Teams Admin Center → Teams apps → Manage apps → encontre seu app → Upload new version
- Opção B (Sideload): No Teams → Apps → Manage your apps → Upload a custom app
- Para canais de team: reinstale o app em cada team para que as novas permissões entrem em vigor
- Feche completamente e reabra o Teams (não apenas feche a janela) para limpar metadados de app em cache
Capacidades: apenas RSC vs Graph
Com apenas RSC do Teams (app instalado, sem permissões de Graph API)
Funciona:
- Ler conteúdo de texto de mensagens de canal.
- Enviar conteúdo de texto em mensagens de canal.
- Receber anexos de arquivo em DMs (pessoal).
Não funciona:
- Conteúdo de imagens ou arquivos em canais/grupos (o payload inclui apenas um stub HTML).
- Download de anexos armazenados no SharePoint/OneDrive.
- Leitura de histórico de mensagens (além do evento de webhook ao vivo).
Com RSC do Teams + permissões de Application do Microsoft Graph
Adiciona:
- Download de conteúdos hospedados (imagens coladas nas mensagens).
- Download de anexos de arquivo armazenados no SharePoint/OneDrive.
- Leitura de histórico de mensagens de canal/chat via Graph.
RSC vs Graph API
| Capacidade | Permissões RSC | Graph API |
|---|---|---|
| Mensagens em tempo real | Sim (via webhook) | Não (apenas polling) |
| Mensagens históricas | Não | Sim (pode consultar histórico) |
| Complexidade de setup | Apenas manifesto | Requer consentimento de admin + fluxo de token |
| Funciona offline | Não (deve estar rodando) | Sim (consulta a qualquer momento) |
Conclusão: RSC é para escuta em tempo real; Graph API é para acesso histórico. Para recuperar mensagens perdidas enquanto offline, você precisa de Graph API com ChannelMessage.Read.All (requer consentimento de admin).
Mídia + histórico com Graph (obrigatório para canais)
Se precisar de imagens/arquivos em canais ou quiser buscar histórico de mensagens, você deve ativar permissões do Microsoft Graph e conceder consentimento de admin.
- No Entra ID (Azure AD) App Registration, adicione permissões de Application do Microsoft Graph:
ChannelMessage.Read.All(anexos de canal + histórico)Chat.Read.AllouChatMessage.Read.All(chats de grupo)
- Conceda consentimento de admin para o tenant.
- Incremente a versão do manifesto do app Teams, re-faça upload e reinstale o app no Teams.
- Feche completamente e reabra o Teams para limpar metadados de app em cache.
Permissão adicional para menções de usuário: menções @usuário funcionam imediatamente para usuários na conversa. No entanto, se quiser buscar e mencionar dinamicamente usuários que não estão na conversa atual, adicione a permissão User.Read.All (Application) e conceda consentimento de admin.
Limitações conhecidas
Timeouts de webhook
O Teams entrega mensagens via webhook HTTP. Se o processamento demorar muito (ex.: respostas lentas de LLM), você pode ver:
- Timeouts do gateway
- Teams reenviando a mensagem (causando duplicatas)
- Respostas perdidas
O OpenClaw lida com isso retornando rapidamente e enviando respostas proativamente, mas respostas muito lentas ainda podem causar problemas.
Formatação
O markdown do Teams é mais limitado que o do Slack ou Discord:
- Formatação básica funciona: negrito, itálico,
código, links - Markdown complexo (tabelas, listas aninhadas) pode não renderizar corretamente
- Adaptive Cards são suportados para enquetes e envio de cards arbitrários (veja abaixo)
Configuração
Configurações principais (veja /gateway/configuration para padrões compartilhados de canal):
channels.msteams.enabled: ativar/desativar o canal.channels.msteams.appId,channels.msteams.appPassword,channels.msteams.tenantId: credenciais do bot.channels.msteams.webhook.port(padrão3978)channels.msteams.webhook.path(padrão/api/messages)channels.msteams.dmPolicy:pairing | allowlist | open | disabled(padrão: pairing)channels.msteams.allowFrom: lista de permitidos de DM (IDs de objeto AAD recomendados). O assistente resolve nomes para IDs durante a configuração quando o acesso ao Graph está disponível.channels.msteams.dangerouslyAllowNameMatching: toggle emergencial para reativar correspondência mutável por UPN/nome de exibição e roteamento direto por nome de team/canal.channels.msteams.textChunkLimit: tamanho do chunk de texto de saída.channels.msteams.chunkMode:length(padrão) ounewlinepara dividir em linhas em branco (limites de parágrafo) antes da fragmentação por tamanho.channels.msteams.mediaAllowHosts: lista de permitidos para hosts de anexos de entrada (padrão: domínios Microsoft/Teams).channels.msteams.mediaAuthAllowHosts: lista de permitidos para anexar headers de Authorization em retries de mídia (padrão: hosts Graph + Bot Framework).channels.msteams.requireMention: exigir @menção em canais/grupos (padrão true).channels.msteams.replyStyle:thread | top-level(veja Estilo de resposta).channels.msteams.teams.<teamId>.replyStyle: override por team.channels.msteams.teams.<teamId>.requireMention: override por team.channels.msteams.teams.<teamId>.tools: overrides de política de ferramentas por team padrão (allow/deny/alsoAllow) usados quando um override de canal está ausente.channels.msteams.teams.<teamId>.toolsBySender: overrides de política de ferramentas por team por remetente padrão (wildcard"*"suportado).channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle: override por canal.channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention: override por canal.channels.msteams.teams.<teamId>.channels.<conversationId>.tools: overrides de política de ferramentas por canal (allow/deny/alsoAllow).channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender: overrides de política de ferramentas por canal por remetente (wildcard"*"suportado).- Chaves de
toolsBySenderdevem usar prefixos explícitos:id:,e164:,username:,name:(chaves legadas sem prefixo ainda mapeiam apenas paraid:). channels.msteams.sharePointSiteId: ID do site SharePoint para uploads de arquivo em chats de grupo/canais (veja Envio de arquivos em chats de grupo).
Roteamento e sessões
- As chaves de sessão seguem o formato padrão de agente (veja /concepts/session):
- Mensagens diretas compartilham a sessão principal (
agent:<agentId>:<mainKey>). - Mensagens de canal/grupo usam ID de conversa:
agent:<agentId>:msteams:channel:<conversationId>agent:<agentId>:msteams:group:<conversationId>
- Mensagens diretas compartilham a sessão principal (
Estilo de resposta: threads vs posts
O Teams introduziu recentemente dois estilos de UI de canal sobre o mesmo modelo de dados subjacente:
| Estilo | Descrição | replyStyle recomendado |
|---|---|---|
| Posts (clássico) | Mensagens aparecem como cards com respostas em thread abaixo | thread (padrão) |
| Threads (tipo Slack) | Mensagens fluem linearmente, mais parecido com o Slack | top-level |
O problema: A API do Teams não expõe qual estilo de UI um canal usa. Se você usar o replyStyle errado:
threadem um canal estilo Threads → respostas aparecem aninhadas de forma estranhatop-levelem um canal estilo Posts → respostas aparecem como posts separados de nível superior em vez de na thread
Solução: Configure replyStyle por canal com base em como o canal está configurado:
{
"msteams": {
"replyStyle": "thread",
"teams": {
"19:[email protected]": {
"channels": {
"19:[email protected]": {
"replyStyle": "top-level"
}
}
}
}
}
}
Anexos e imagens
Limitações atuais:
- DMs: Imagens e anexos de arquivo funcionam via APIs de arquivo de bot do Teams.
- Canais/grupos: Anexos ficam no armazenamento M365 (SharePoint/OneDrive). O payload do webhook inclui apenas um stub HTML, não os bytes reais do arquivo. Permissões de Graph API são obrigatórias para baixar anexos de canal.
Sem permissões do Graph, mensagens de canal com imagens são recebidas como apenas texto (o conteúdo da imagem não é acessível ao bot).
Por padrão, o OpenClaw só baixa mídia de hostnames da Microsoft/Teams. Sobrescreva com channels.msteams.mediaAllowHosts (use ["*"] para permitir qualquer host).
Headers de Authorization são anexados apenas para hosts em channels.msteams.mediaAuthAllowHosts (padrão: hosts Graph + Bot Framework). Mantenha essa lista restrita (evite sufixos multi-tenant).
Envio de arquivos em chats de grupo
Bots podem enviar arquivos em DMs usando o fluxo FileConsentCard (integrado). No entanto, enviar arquivos em chats de grupo/canais requer configuração adicional:
| Contexto | Como os arquivos são enviados | Configuração necessária |
|---|---|---|
| DMs | FileConsentCard → usuário aceita → bot envia | Funciona sem configuração adicional |
| Chats de grupo/canais | Upload para SharePoint → link de compartilhamento | Requer sharePointSiteId + permissões do Graph |
| Imagens (qualquer contexto) | Base64 inline | Funciona sem configuração adicional |
Por que chats de grupo precisam do SharePoint
Bots não têm um drive OneDrive pessoal (o endpoint /me/drive da Graph API não funciona para identidades de aplicativo). Para enviar arquivos em chats de grupo/canais, o bot faz upload para um site SharePoint e cria um link de compartilhamento.
Configuração
-
Adicione permissões de Graph API no Entra ID (Azure AD) → App Registration:
Sites.ReadWrite.All(Application) - upload de arquivos para o SharePointChat.Read.All(Application) - opcional, permite links de compartilhamento por usuário
-
Conceda consentimento de admin para o tenant.
-
Obtenha o ID do site SharePoint:
# Via Graph Explorer ou curl com um token válido: curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}" # Exemplo: para um site em "contoso.sharepoint.com/sites/BotFiles" curl -H "Authorization: Bearer $TOKEN" \ "https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/BotFiles" # A resposta inclui: "id": "contoso.sharepoint.com,guid1,guid2" -
Configure o OpenClaw:
{ channels: { msteams: { // ... other config ... sharePointSiteId: "contoso.sharepoint.com,guid1,guid2", }, }, }
Comportamento de compartilhamento
| Permissão | Comportamento de compartilhamento |
|---|---|
Apenas Sites.ReadWrite.All | Link de compartilhamento organizacional (qualquer pessoa na org pode acessar) |
Sites.ReadWrite.All + Chat.Read.All | Link de compartilhamento por usuário (apenas membros do chat podem acessar) |
O compartilhamento por usuário é mais seguro, pois apenas os participantes do chat podem acessar o arquivo. Se a permissão Chat.Read.All estiver ausente, o bot recorre ao compartilhamento organizacional.
Comportamento de fallback
| Cenário | Resultado |
|---|---|
Chat de grupo + arquivo + sharePointSiteId configurado | Upload para SharePoint, envia link de compartilhamento |
Chat de grupo + arquivo + sem sharePointSiteId | Tenta upload OneDrive (pode falhar), envia apenas texto |
| Chat pessoal + arquivo | Fluxo FileConsentCard (funciona sem SharePoint) |
| Qualquer contexto + imagem | Base64 inline (funciona sem SharePoint) |
Local de armazenamento dos arquivos
Arquivos enviados são armazenados em uma pasta /OpenClawShared/ na biblioteca de documentos padrão do site SharePoint configurado.
Enquetes (Adaptive Cards)
O OpenClaw envia enquetes do Teams como Adaptive Cards (não existe API nativa de enquete do Teams).
- CLI:
openclaw message poll --channel msteams --target conversation:<id> ... - Votos são registrados pelo gateway em
~/.openclaw/msteams-polls.json. - O gateway deve permanecer online para registrar votos.
- As enquetes ainda não publicam resumos de resultados automaticamente (inspecione o arquivo de armazenamento se necessário).
Adaptive Cards (arbitrários)
Envie qualquer JSON de Adaptive Card para usuários ou conversas do Teams usando a ferramenta message ou CLI.
O parâmetro card aceita um objeto JSON de Adaptive Card. Quando card é fornecido, o texto da mensagem é opcional.
Ferramenta do agente:
{
"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!"}]}'
Veja a documentação de Adaptive Cards para esquema e exemplos de cards. Para detalhes de formato de alvo, veja Formatos de alvo abaixo.
Formatos de alvo
Alvos do MSTeams usam prefixos para distinguir entre usuários e conversas:
| Tipo de alvo | Formato | Exemplo |
|---|---|---|
| Usuário (por ID) | user:<aad-object-id> | user:40a1a0ed-4ff2-4164-a219-55518990c197 |
| Usuário (por nome) | user:<display-name> | user:John Smith (requer Graph API) |
| Grupo/canal | conversation:<conversation-id> | conversation:19:[email protected] |
| Grupo/canal (bruto) | <conversation-id> | 19:[email protected] (se contém @thread) |
Exemplos CLI:
# Enviar para um usuário por ID
openclaw message send --channel msteams --target "user:40a1a0ed-..." --message "Hello"
# Enviar para um usuário por nome de exibição (aciona lookup na Graph API)
openclaw message send --channel msteams --target "user:John Smith" --message "Hello"
# Enviar para um chat de grupo ou canal
openclaw message send --channel msteams --target "conversation:19:[email protected]" --message "Hello"
# Enviar um Adaptive Card para uma conversa
openclaw message send --channel msteams --target "conversation:19:[email protected]" \
--card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello"}]}'
Exemplos da ferramenta do agente:
{
"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" }]
}
}
Observação: sem o prefixo user:, nomes são resolvidos como grupo/team. Sempre use user: ao direcionar pessoas pelo nome de exibição.
Mensagens proativas
- Mensagens proativas só são possíveis após o usuário ter interagido, porque armazenamos referências de conversa nesse momento.
- Veja
/gateway/configurationpara controles dedmPolicye lista de permitidos.
IDs de team e canal (armadilha comum)
O parâmetro de query groupId nas URLs do Teams NÃO é o ID do team usado para configuração. Extraia os IDs do caminho da URL:
URL do team:
https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
└────────────────────────────┘
Team ID (decodifique a URL)
URL do canal:
https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
└─────────────────────────┘
Channel ID (decodifique a URL)
Para configuração:
- Team ID = segmento do caminho após
/team/(decodificado, ex.:19:[email protected]) - Channel ID = segmento do caminho após
/channel/(decodificado) - Ignore o parâmetro de query
groupId
Canais privados
Bots têm suporte limitado em canais privados:
| Recurso | Canais padrão | Canais privados |
|---|---|---|
| Instalação do bot | Sim | Limitado |
| Mensagens em tempo real (webhook) | Sim | Pode não funcionar |
| Permissões RSC | Sim | Pode se comportar diferente |
| @menções | Sim | Se o bot estiver acessível |
| Histórico via Graph API | Sim | Sim (com permissões) |
Soluções se canais privados não funcionarem:
- Use canais padrão para interações com o bot
- Use DMs - usuários sempre podem enviar mensagens diretamente ao bot
- Use Graph API para acesso histórico (requer
ChannelMessage.Read.All)
Solução de problemas
Problemas comuns
- Imagens não aparecem em canais: permissões do Graph ou consentimento de admin ausentes. Reinstale o app Teams e feche/reabra o Teams completamente.
- Sem respostas em canal: menções são obrigatórias por padrão; defina
channels.msteams.requireMention=falseou configure por team/canal. - Incompatibilidade de versão (Teams ainda mostra manifesto antigo): remova + re-adicione o app e feche o Teams completamente para atualizar.
- 401 Unauthorized do webhook: Esperado ao testar manualmente sem JWT do Azure - significa que o endpoint é acessível mas a autenticação falhou. Use Azure Web Chat para testar corretamente.
Erros de upload do manifesto
- “Icon file cannot be empty”: O manifesto referencia arquivos de ícone que têm 0 bytes. Crie ícones PNG válidos (32x32 para
outline.png, 192x192 paracolor.png). - “webApplicationInfo.Id already in use”: O app ainda está instalado em outro team/chat. Encontre e desinstale primeiro, ou aguarde 5-10 minutos para propagação.
- “Something went wrong” no upload: Faça upload via https://admin.teams.microsoft.com, abra o DevTools do navegador (F12) → aba Network e verifique o corpo da resposta para o erro real.
- Sideload falhando: Tente “Upload an app to your org’s app catalog” em vez de “Upload a custom app” - isso frequentemente contorna restrições de sideload.
Permissões RSC não funcionando
- Verifique se
webApplicationInfo.idcorresponde exatamente ao App ID do bot - Re-faça upload do app e reinstale no team/chat
- Verifique se o admin da organização bloqueou permissões RSC
- Confirme que está usando o escopo correto:
ChannelMessage.Read.Grouppara teams,ChatMessage.Read.Chatpara chats de grupo
Referências
- Criar Azure Bot - Guia de configuração do Azure Bot
- Portal de Desenvolvedores do Teams - criar/gerenciar apps Teams
- Esquema de manifesto de app Teams
- Receber mensagens de canal com RSC
- Referência de permissões RSC
- Tratamento de arquivos de bot do Teams (canal/grupo requer Graph)
- Mensagens proativas