Saltar al contenido principal

Microsoft Teams (plugin)

“Abandonen toda esperanza quienes entren aquí.”
Actualizado: 2026-01-21 Estado: se admiten texto + archivos adjuntos en mensajes directos; el envío de archivos en canales/grupos requiere sharePointSiteId + permisos de Graph (consulte Envío de archivos en chats grupales). Las encuestas se envían mediante Adaptive Cards.

Plugin requerido

Microsoft Teams se distribuye como un plugin y no viene incluido con la instalación principal. Cambio disruptivo (2026.1.15): MS Teams salió del núcleo. Si lo usa, debe instalar el plugin. Explicación: mantiene las instalaciones del núcleo más ligeras y permite que las dependencias de MS Teams se actualicen de forma independiente. Instalar vía CLI (registro npm):
openclaw plugins install @openclaw/msteams
Instalación local (cuando se ejecuta desde un repositorio git):
openclaw plugins install ./extensions/msteams
Si elige Teams durante la configuración/onboarding y se detecta un checkout de git, OpenClaw ofrecerá automáticamente la ruta de instalación local. Detalles: Plugins

Configuración rápida (principiante)

  1. Instale el plugin de Microsoft Teams.
  2. Cree un Azure Bot (App ID + secreto del cliente + ID de tenant).
  3. Configure OpenClaw con esas credenciales.
  4. Exponga /api/messages (puerto 3978 por defecto) mediante una URL pública o un túnel.
  5. Instale el paquete de la app de Teams e inicie el gateway.
Configuración mínima:
{
  channels: {
    msteams: {
      enabled: true,
      appId: "<APP_ID>",
      appPassword: "<APP_PASSWORD>",
      tenantId: "<TENANT_ID>",
      webhook: { port: 3978, path: "/api/messages" },
    },
  },
}
Nota: los chats grupales están bloqueados por defecto (channels.msteams.groupPolicy: "allowlist"). Para permitir respuestas en grupos, configure channels.msteams.groupAllowFrom (o use groupPolicy: "open" para permitir a cualquier miembro, con mención obligatoria).

Objetivos

  • Comunicarse con OpenClaw mediante mensajes directos de Teams, chats grupales o canales.
  • Mantener un enrutamiento determinista: las respuestas siempre vuelven al canal por el que llegaron.
  • Usar por defecto un comportamiento seguro del canal (menciones requeridas salvo que se configure lo contrario).

Escrituras de configuración

De forma predeterminada, Microsoft Teams puede escribir actualizaciones de configuración activadas por /config set|unset (requiere commands.config: true). Deshabilitar con:
{
  channels: { msteams: { configWrites: false } },
}

Control de acceso (mensajes directos + grupos)

Acceso a mensajes directos
  • Predeterminado: channels.msteams.dmPolicy = "pairing". Los remitentes desconocidos se ignoran hasta ser aprobados.
  • channels.msteams.allowFrom acepta IDs de objetos AAD, UPNs o nombres para mostrar. El asistente resuelve nombres a IDs mediante Microsoft Graph cuando las credenciales lo permiten.
Acceso a grupos
  • Predeterminado: channels.msteams.groupPolicy = "allowlist" (bloqueado a menos que agregue groupAllowFrom). Use channels.defaults.groupPolicy para anular el valor predeterminado cuando no esté configurado.
  • channels.msteams.groupAllowFrom controla qué remitentes pueden activar en chats/canales grupales (usa como respaldo channels.msteams.allowFrom).
  • Configure groupPolicy: "open" para permitir a cualquier miembro (aún con mención obligatoria por defecto).
  • Para permitir ningún canal, configure channels.msteams.groupPolicy: "disabled".
Ejemplo:
{
  channels: {
    msteams: {
      groupPolicy: "allowlist",
      groupAllowFrom: ["[email protected]"],
    },
  },
}
Teams + lista de permitidos de canales
  • Limite respuestas por grupo/canal listando equipos y canales bajo channels.msteams.teams.
  • Las claves pueden ser IDs o nombres de equipos; las claves de canal pueden ser IDs de conversación o nombres.
  • Cuando groupPolicy="allowlist" y existe una lista de permitidos de equipos, solo se aceptan los equipos/canales listados (con mención obligatoria).
  • El asistente de configuración acepta entradas Team/Channel y las almacena por usted.
  • Al iniciar, OpenClaw resuelve nombres de equipos/canales y listas de permitidos de usuarios a IDs (cuando los permisos de Graph lo permiten) y registra el mapeo; las entradas no resueltas se conservan tal como se escribieron.
Ejemplo:
{
  channels: {
    msteams: {
      groupPolicy: "allowlist",
      teams: {
        "My Team": {
          channels: {
            General: { requireMention: true },
          },
        },
      },
    },
  },
}

Cómo funciona

  1. Instale el plugin de Microsoft Teams.
  2. Cree un Azure Bot (App ID + secreto + ID de tenant).
  3. Cree un paquete de app de Teams que haga referencia al bot e incluya los permisos RSC a continuación.
  4. Cargue/instale la app de Teams en un equipo (o en ámbito personal para mensajes directos).
  5. Configure msteams en ~/.openclaw/openclaw.json (o variables de entorno) e inicie el gateway.
  6. El gateway escucha tráfico de webhook de Bot Framework en /api/messages por defecto.

Configuración del Azure Bot (Requisitos previos)

Antes de configurar OpenClaw, debe crear un recurso de Azure Bot.

Paso 1: Crear Azure Bot

  1. Vaya a Crear Azure Bot
  2. Complete la pestaña Basics:
    CampoValor
    Bot handleNombre de su bot, p. ej., openclaw-msteams (debe ser único)
    SubscriptionSeleccione su suscripción de Azure
    Resource groupCree uno nuevo o use uno existente
    Pricing tierFree para dev/pruebas
    Type of AppSingle Tenant (recomendado; ver nota abajo)
    Creation typeCreate new Microsoft App ID
Aviso de deprecación: La creación de nuevos bots multi-tenant se deprecó después del 2025-07-31. Use Single Tenant para nuevos bots.
  1. Haga clic en Review + createCreate (espere ~1-2 minutos)

Paso 2: Obtener credenciales

  1. Vaya a su recurso de Azure Bot → Configuration
  2. Copie Microsoft App ID → este es su appId
  3. Haga clic en Manage Password → vaya al App Registration
  4. En Certificates & secretsNew client secret → copie el Value → este es su appPassword
  5. Vaya a Overview → copie Directory (tenant) ID → este es su tenantId

Paso 3: Configurar el endpoint de mensajería

  1. En Azure Bot → Configuration
  2. Establezca Messaging endpoint en la URL de su webhook:
    • Producción: https://your-domain.com/api/messages
    • Desarrollo local: use un túnel (consulte Desarrollo local abajo)

Paso 4: Habilitar el canal de Teams

  1. En Azure Bot → Channels
  2. Haga clic en Microsoft Teams → Configure → Save
  3. Acepte los Términos del servicio

Desarrollo local (túneles)

Teams no puede alcanzar localhost. Use un túnel para desarrollo local: Opción A: ngrok
ngrok http 3978
# Copy the https URL, e.g., https://abc123.ngrok.io
# Set messaging endpoint to: https://abc123.ngrok.io/api/messages
Opción B: Tailscale Funnel
tailscale funnel 3978
# Use your Tailscale funnel URL as the messaging endpoint

Portal para desarrolladores de Teams (alternativa)

En lugar de crear manualmente un ZIP de manifiesto, puede usar el Portal para desarrolladores de Teams:
  1. Haga clic en + New app
  2. Complete la información básica (nombre, descripción, info del desarrollador)
  3. Vaya a App featuresBot
  4. Seleccione Enter a bot ID manually y pegue el App ID de su Azure Bot
  5. Marque los ámbitos: Personal, Team, Group Chat
  6. Haga clic en DistributeDownload app package
  7. En Teams: AppsManage your appsUpload a custom app → seleccione el ZIP
Suele ser más fácil que editar manifiestos JSON a mano.

Prueba del bot

Opción A: Azure Web Chat (verifique primero el webhook)
  1. En Azure Portal → su recurso de Azure Bot → Test in Web Chat
  2. Envíe un mensaje: debería ver una respuesta
  3. Esto confirma que su endpoint de webhook funciona antes de configurar Teams
Opción B: Teams (después de instalar la app)
  1. Instale la app de Teams (sideload o catálogo de la organización)
  2. Busque el bot en Teams y envíe un mensaje directo
  3. Revise los logs del gateway para actividad entrante

Configuración (mínima solo texto)

  1. Instale el plugin de Microsoft Teams
    • Desde npm: openclaw plugins install @openclaw/msteams
    • Desde un checkout local: openclaw plugins install ./extensions/msteams
  2. Registro del bot
    • Cree un Azure Bot (ver arriba) y anote:
      • App ID
      • Secreto del cliente (contraseña de la app)
      • Tenant ID (single-tenant)
  3. Manifiesto de la app de Teams
    • Incluya una entrada bot con botId = <App ID>.
    • Ámbitos: personal, team, groupChat.
    • supportsFiles: true (requerido para manejo de archivos en ámbito personal).
    • Agregue permisos RSC (abajo).
    • Cree íconos: outline.png (32x32) y color.png (192x192).
    • Comprima los tres archivos juntos: manifest.json, outline.png, color.png.
  4. Configure OpenClaw
    {
      "msteams": {
        "enabled": true,
        "appId": "<APP_ID>",
        "appPassword": "<APP_PASSWORD>",
        "tenantId": "<TENANT_ID>",
        "webhook": { "port": 3978, "path": "/api/messages" }
      }
    }
    
    También puede usar variables de entorno en lugar de claves de configuración:
    • MSTEAMS_APP_ID
    • MSTEAMS_APP_PASSWORD
    • MSTEAMS_TENANT_ID
  5. Endpoint del bot
    • Establezca el Messaging Endpoint del Azure Bot en:
      • https://<host>:3978/api/messages (o su ruta/puerto elegido).
  6. Ejecute el gateway
    • El canal de Teams se inicia automáticamente cuando el plugin está instalado y existe la configuración msteams con credenciales.

Contexto de historial

  • channels.msteams.historyLimit controla cuántos mensajes recientes de canal/grupo se envuelven en el prompt.
  • Usa como respaldo messages.groupChat.historyLimit. Configure 0 para deshabilitar (predeterminado 50).
  • El historial de mensajes directos puede limitarse con channels.msteams.dmHistoryLimit (turnos por usuario). Anulaciones por usuario: channels.msteams.dms["<user_id>"].historyLimit.

Permisos RSC actuales de Teams (manifiesto)

Estos son los resourceSpecific permissions existentes en nuestro manifiesto de la app de Teams. Solo aplican dentro del equipo/chat donde está instalada la app. Para canales (ámbito de equipo):
  • ChannelMessage.Read.Group (Application) - recibir todos los mensajes del canal sin @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)
Para chats grupales:
  • ChatMessage.Read.Chat (Application) - recibir todos los mensajes del chat grupal sin @mention

Ejemplo de manifiesto de Teams (redactado)

Ejemplo mínimo y válido con los campos requeridos. Reemplace IDs y 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" }
      ]
    }
  }
}

Advertencias del manifiesto (campos imprescindibles)

  • bots[].botId debe coincidir con el App ID del Azure Bot.
  • webApplicationInfo.id debe coincidir con el App ID del Azure Bot.
  • bots[].scopes debe incluir las superficies que planea usar (personal, team, groupChat).
  • bots[].supportsFiles: true es requerido para manejo de archivos en ámbito personal.
  • authorization.permissions.resourceSpecific debe incluir lectura/envío de canales si desea tráfico de canales.

Actualizar una app existente

Para actualizar una app de Teams ya instalada (p. ej., para agregar permisos RSC):
  1. Actualice su manifest.json con la nueva configuración
  2. Incremente el campo version (p. ej., 1.0.01.1.0)
  3. Vuelva a comprimir el manifiesto con los íconos (manifest.json, outline.png, color.png)
  4. Cargue el nuevo zip:
    • Opción A (Teams Admin Center): Teams Admin Center → Teams apps → Manage apps → busque su app → Upload new version
    • Opción B (Sideload): En Teams → Apps → Manage your apps → Upload a custom app
  5. Para canales de equipo: Reinstale la app en cada equipo para que los nuevos permisos surtan efecto
  6. Cierre completamente y vuelva a abrir Teams (no solo cerrar la ventana) para limpiar la caché de metadatos de la app

Capacidades: solo RSC vs Graph

Con solo Teams RSC (app instalada, sin permisos de Graph API)

Funciona:
  • Leer contenido de texto de mensajes de canal.
  • Enviar contenido de texto de mensajes de canal.
  • Recibir archivos adjuntos personales (DM).
No funciona:
  • Contenido de imágenes o archivos en canales/grupos (la carga solo incluye un stub HTML).
  • Descargar adjuntos almacenados en SharePoint/OneDrive.
  • Leer historial de mensajes (más allá del evento de webhook en vivo).

Con Teams RSC + permisos de aplicación de Microsoft Graph

Agrega:
  • Descarga de contenidos alojados (imágenes pegadas en mensajes).
  • Descarga de archivos adjuntos almacenados en SharePoint/OneDrive.
  • Lectura del historial de mensajes de canal/chat vía Graph.

RSC vs Graph API

CapacidadPermisos RSCGraph API
Mensajes en tiempo realSí (vía webhook)No (solo sondeo)
Mensajes históricosNoSí (se puede consultar historial)
Complejidad de configuraciónSolo manifiesto de la appRequiere consentimiento de admin + flujo de tokens
Funciona sin conexiónNo (debe estar en ejecución)Sí (consultar en cualquier momento)
Conclusión: RSC es para escucha en tiempo real; Graph API es para acceso histórico. Para ponerse al día con mensajes perdidos mientras estaba offline, necesita Graph API con ChannelMessage.Read.All (requiere consentimiento de administrador).

Medios + historial habilitados con Graph (requerido para canales)

Si necesita imágenes/archivos en canales o desea obtener historial de mensajes, debe habilitar permisos de Microsoft Graph y otorgar consentimiento de administrador.
  1. En Entra ID (Azure AD) App Registration, agregue permisos de Application de Microsoft Graph:
    • ChannelMessage.Read.All (adjuntos de canal + historial)
    • Chat.Read.All o ChatMessage.Read.All (chats grupales)
  2. Otorgue consentimiento de administrador para el tenant.
  3. Aumente la versión del manifiesto de la app de Teams, vuelva a cargarla y reinstale la app en Teams.
  4. Cierre completamente y vuelva a abrir Teams para limpiar la caché de metadatos de la app.
Permiso adicional para menciones de usuario: Las @menciones de usuario funcionan de inmediato para los usuarios en la conversación. Sin embargo, si quieres buscar y mencionar dinámicamente a usuarios que no están en la conversación actual, añade el permiso User.Read.All (Application) y concede el consentimiento de administrador.

Limitaciones conocidas

Tiempos de espera del webhook

Teams entrega mensajes mediante webhook HTTP. Si el procesamiento tarda demasiado (p. ej., respuestas lentas del LLM), puede ver:
  • Tiempos de espera del gateway
  • Reintentos de Teams (causando duplicados)
  • Respuestas perdidas
OpenClaw maneja esto devolviendo rápidamente y enviando respuestas de forma proactiva, pero respuestas muy lentas aún pueden causar problemas.

Formato

El markdown de Teams es más limitado que Slack o Discord:
  • El formato básico funciona: negrita, cursiva, code, enlaces
  • El markdown complejo (tablas, listas anidadas) puede no renderizarse correctamente
  • Adaptive Cards son compatibles para encuestas y envíos arbitrarios de tarjetas (ver abajo)

Configuración

Ajustes clave (consulte /gateway/configuration para patrones de canales compartidos):
  • channels.msteams.enabled: habilitar/deshabilitar el canal.
  • channels.msteams.appId, channels.msteams.appPassword, channels.msteams.tenantId: credenciales del bot.
  • channels.msteams.webhook.port (predeterminado 3978)
  • channels.msteams.webhook.path (predeterminado /api/messages)
  • channels.msteams.dmPolicy: pairing | allowlist | open | disabled (predeterminado: emparejamiento)
  • channels.msteams.allowFrom: lista de permitidos para mensajes directos (IDs de objeto AAD, UPNs o nombres para mostrar). El asistente resuelve nombres a IDs durante la configuración cuando hay acceso a Graph.
  • channels.msteams.textChunkLimit: tamaño de fragmento de texto saliente.
  • channels.msteams.chunkMode: length (predeterminado) o newline para dividir en líneas en blanco (límites de párrafo) antes del troceado por longitud.
  • channels.msteams.mediaAllowHosts: lista de permitidos de hosts de adjuntos entrantes (predeterminado: dominios de Microsoft/Teams).
  • channels.msteams.mediaAuthAllowHosts: lista de permitidos para adjuntar encabezados Authorization en reintentos de medios (predeterminado: hosts de Graph + Bot Framework).
  • channels.msteams.requireMention: requerir @mention en canales/grupos (predeterminado true).
  • channels.msteams.replyStyle: thread | top-level (consulte Estilo de respuesta).
  • channels.msteams.teams.<teamId>.replyStyle: anulación por equipo.
  • channels.msteams.teams.<teamId>.requireMention: anulación por equipo.
  • channels.msteams.teams.<teamId>.tools: anulaciones predeterminadas de política de herramientas por equipo (allow/deny/alsoAllow) usadas cuando falta una anulación de canal.
  • channels.msteams.teams.<teamId>.toolsBySender: anulaciones predeterminadas de política de herramientas por equipo y remitente ("*" comodín compatible).
  • channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle: anulación por canal.
  • channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention: anulación por canal.
  • channels.msteams.teams.<teamId>.channels.<conversationId>.tools: anulaciones de política de herramientas por canal (allow/deny/alsoAllow).
  • channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender: anulaciones de política de herramientas por canal y remitente ("*" comodín compatible).
  • channels.msteams.sharePointSiteId: ID del sitio de SharePoint para cargas de archivos en chats/canales grupales (consulte Envío de archivos en chats grupales).

Enrutamiento y sesiones

  • Las claves de sesión siguen el formato estándar del agente (consulte /concepts/session):
    • Los mensajes directos comparten la sesión principal (agent:<agentId>:<mainKey>).
    • Los mensajes de canal/grupo usan el id de conversación:
      • agent:<agentId>:msteams:channel:<conversationId>
      • agent:<agentId>:msteams:group:<conversationId>

Estilo de respuesta: Hilos vs Publicaciones

Teams introdujo recientemente dos estilos de UI de canal sobre el mismo modelo de datos subyacente:
EstiloDescripciónreplyStyle recomendado
Publicaciones (clásico)Los mensajes aparecen como tarjetas con respuestas en hilo debajothread (predeterminado)
Hilos (tipo Slack)Los mensajes fluyen linealmente, más como Slacktop-level
El problema: La API de Teams no expone qué estilo de UI usa un canal. Si usa el replyStyle incorrecto:
  • thread en un canal con estilo Hilos → las respuestas aparecen anidadas de forma incómoda
  • top-level en un canal con estilo Publicaciones → las respuestas aparecen como publicaciones de nivel superior separadas en lugar de en hilo
Solución: Configure replyStyle por canal según cómo esté configurado el canal:
{
  "msteams": {
    "replyStyle": "thread",
    "teams": {
      "19:[email protected]": {
        "channels": {
          "19:[email protected]": {
            "replyStyle": "top-level"
          }
        }
      }
    }
  }
}

Adjuntos e imágenes

Limitaciones actuales:
  • Mensajes directos: Imágenes y archivos adjuntos funcionan mediante las APIs de archivos del bot de Teams.
  • Canales/grupos: Los adjuntos viven en el almacenamiento M365 (SharePoint/OneDrive). La carga del webhook solo incluye un stub HTML, no los bytes reales del archivo. Se requieren permisos de Graph API para descargar adjuntos de canales.
Sin permisos de Graph, los mensajes de canal con imágenes se recibirán solo como texto (el contenido de la imagen no es accesible para el bot). Por defecto, OpenClaw solo descarga medios desde nombres de host de Microsoft/Teams. Anule con channels.msteams.mediaAllowHosts (use ["*"] para permitir cualquier host). Los encabezados Authorization solo se adjuntan para hosts en channels.msteams.mediaAuthAllowHosts (predeterminado: hosts de Graph + Bot Framework). Mantenga esta lista estricta (evite sufijos multi-tenant).

Envío de archivos en chats grupales

Los bots pueden enviar archivos en mensajes directos usando el flujo FileConsentCard (integrado). Sin embargo, enviar archivos en chats/canales grupales requiere configuración adicional:
ContextoCómo se envían los archivosConfiguración necesaria
Mensajes directosFileConsentCard → el usuario acepta → el bot cargaFunciona fuera de la caja
Chats/canales grupalesCarga a SharePoint → enlace compartidoRequiere sharePointSiteId + permisos de Graph
Imágenes (cualquier contexto)Inline codificado en Base64Funciona fuera de la caja

Por qué los chats grupales necesitan SharePoint

Los bots no tienen una unidad personal de OneDrive (el endpoint de Graph /me/drive no funciona para identidades de aplicación). Para enviar archivos en chats/canales grupales, el bot carga a un sitio de SharePoint y crea un enlace de uso compartido.

Configuración

  1. Agregue permisos de Graph API en Entra ID (Azure AD) → App Registration:
    • Sites.ReadWrite.All (Application) - cargar archivos a SharePoint
    • Chat.Read.All (Application) - opcional, habilita enlaces de uso compartido por usuario
  2. Otorgue consentimiento de administrador para el tenant.
  3. Obtenga el ID de su sitio de SharePoint:
    # 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"
    
  4. Configure OpenClaw:
    {
      channels: {
        msteams: {
          // ... other config ...
          sharePointSiteId: "contoso.sharepoint.com,guid1,guid2",
        },
      },
    }
    

Comportamiento de uso compartido

PermisoComportamiento de uso compartido
Sites.ReadWrite.All solamenteEnlace de uso compartido a nivel de organización (cualquiera en la org puede acceder)
Sites.ReadWrite.All + Chat.Read.AllEnlace de uso compartido por usuario (solo miembros del chat pueden acceder)
El uso compartido por usuario es más seguro, ya que solo los participantes del chat pueden acceder al archivo. Si falta el permiso Chat.Read.All, el bot recurre al uso compartido a nivel de organización.

Comportamiento de respaldo

EscenarioResultado
Chat grupal + archivo + sharePointSiteId configuradoCarga a SharePoint, envía enlace compartido
Chat grupal + archivo + sin sharePointSiteIdIntenta carga a OneDrive (puede fallar), envía solo texto
Chat personal + archivoFlujo FileConsentCard (funciona sin SharePoint)
Cualquier contexto + imagenInline codificado en Base64 (funciona sin SharePoint)

Ubicación de almacenamiento de archivos

Los archivos cargados se almacenan en una carpeta /OpenClawShared/ en la biblioteca de documentos predeterminada del sitio de SharePoint configurado.

Encuestas (Adaptive Cards)

OpenClaw envía encuestas de Teams como Adaptive Cards (no existe una API nativa de encuestas de Teams).
  • CLI: openclaw message poll --channel msteams --target conversation:<id> ...
  • Los votos se registran por el gateway en ~/.openclaw/msteams-polls.json.
  • El gateway debe permanecer en línea para registrar votos.
  • Las encuestas aún no publican automáticamente resúmenes de resultados (inspeccione el archivo de almacenamiento si es necesario).

Adaptive Cards (arbitrarias)

Envíe cualquier JSON de Adaptive Card a usuarios o conversaciones de Teams usando la herramienta o CLI message. El parámetro card acepta un objeto JSON de Adaptive Card. Cuando se proporciona card, el texto del mensaje es opcional. Herramienta del 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!"}]}'
Consulte la documentación de Adaptive Cards para el esquema y ejemplos. Para detalles del formato de destino, consulte Formatos de destino abajo.

Formatos de destino

Los destinos de MSTeams usan prefijos para distinguir entre usuarios y conversaciones:
Tipo de destinoFormatoEjemplo
Usuario (por ID)user:<aad-object-id>user:40a1a0ed-4ff2-4164-a219-55518990c197
Usuario (por nombre)user:<display-name>user:John Smith (requiere Graph API)
Grupo/canalconversation:<conversation-id>conversation:19:[email protected]
Grupo/canal (raw)<conversation-id>19:[email protected] (si contiene @thread)
Ejemplos de 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 an Adaptive Card to a conversation
openclaw message send --channel msteams --target "conversation:19:[email protected]" \
  --card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello"}]}'
Ejemplos de herramienta del 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" }]
  }
}
Nota: Sin el prefijo user:, los nombres se resuelven por defecto a grupos/equipos. Use siempre user: cuando apunte a personas por nombre para mostrar.

Mensajería proactiva

  • Los mensajes proactivos solo son posibles después de que un usuario haya interactuado, porque almacenamos referencias de conversación en ese punto.
  • Consulte /gateway/configuration para dmPolicy y el control por lista de permitidos.

IDs de equipo y canal (error común)

El parámetro de consulta groupId en las URLs de Teams NO es el ID de equipo usado para la configuración. Extraiga los IDs desde la ruta de la URL: URL del equipo:
https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
                                    └────────────────────────────┘
                                    Team ID (URL-decode this)
URL del canal:
https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
                                      └─────────────────────────┘
                                      Channel ID (URL-decode this)
Para configuración:
  • ID de equipo = segmento de ruta después de /team/ (decodificado de URL, p. ej., 19:[email protected])
  • ID de canal = segmento de ruta después de /channel/ (decodificado de URL)
  • Ignore el parámetro de consulta groupId

Canales privados

Los bots tienen soporte limitado en canales privados:
FunciónCanales estándarCanales privados
Instalación del botLimitado
Mensajes en tiempo real (webhook)Puede no funcionar
Permisos RSCPueden comportarse distinto
@mentionsSi el bot es accesible
Historial por Graph APISí (con permisos)
Alternativas si los canales privados no funcionan:
  1. Use canales estándar para interacciones con el bot
  2. Use mensajes directos: los usuarios siempre pueden escribirle al bot directamente
  3. Use Graph API para acceso histórico (requiere ChannelMessage.Read.All)

Problemas comunes

Problemas comunes

  • Las imágenes no se muestran en canales: faltan permisos de Graph o consentimiento de administrador. Reinstale la app de Teams y cierre/abra completamente Teams.
  • Sin respuestas en canal: las menciones son obligatorias por defecto; configure channels.msteams.requireMention=false o ajuste por equipo/canal.
  • Desajuste de versión (Teams aún muestra el manifiesto antiguo): quite y vuelva a agregar la app y cierre completamente Teams para refrescar.
  • 401 Unauthorized desde el webhook: esperado al probar manualmente sin JWT de Azure; indica que el endpoint es alcanzable pero falló la autenticación. Use Azure Web Chat para probar correctamente.

Errores al cargar el manifiesto

  • “Icon file cannot be empty”: El manifiesto referencia íconos de 0 bytes. Cree íconos PNG válidos (32x32 para outline.png, 192x192 para color.png).
  • “webApplicationInfo.Id already in use”: La app aún está instalada en otro equipo/chat. Encuéntrela y desinstálela primero, o espere 5-10 minutos para la propagación.
  • “Something went wrong” al cargar: Cargue mediante https://admin.teams.microsoft.com en su lugar, abra las DevTools del navegador (F12) → pestaña Network, y revise el cuerpo de la respuesta para el error real.
  • Fallo de sideload: Intente “Upload an app to your org’s app catalog” en lugar de “Upload a custom app”; a menudo evita restricciones de sideload.

Permisos RSC no funcionan

  1. Verifique que webApplicationInfo.id coincida exactamente con el App ID de su bot
  2. Vuelva a cargar la app y reinstálela en el equipo/chat
  3. Verifique si el admin de su organización bloqueó los permisos RSC
  4. Confirme que usa el ámbito correcto: ChannelMessage.Read.Group para equipos, ChatMessage.Read.Chat para chats grupales

Referencias