Portabilidad de una aplicación Slack Bolt para JavaScript a Teams

Esta guía le ayudará a migrar una aplicación existente de Slack Bolt para JavaScript a Teams.

Introducción

Al igual que Slack Bolt, el SDK de Teams está diseñado para interactuar con las API de back-end de Teams para crear aplicaciones conversacionales. Ambos SDK proporcionan abstracciones para controlar los eventos, mensajes e interacciones entrantes, así como para enviar respuestas a los usuarios. Si ya tiene un bot de Slack, los conceptos deberían resultarle familiares.

Sin embargo, hay algunas diferencias clave, como la instalación de aplicaciones. En Slack, las aplicaciones se instalan en áreas de trabajo a través de OAuth, mientras que en Teams se instalan a través de la App Store de Teams. Además, las aplicaciones de Teams pueden ser instaladas personalmente por usuarios individuales o en ámbitos de colaboración como chats grupales, canales y reuniones.

Echemos un vistazo a algunas similitudes y diferencias entre los conceptos de Slack y Teams:

Concepto Teams Margen de demora
Instalación Instalado a través de la tienda de aplicaciones por ámbito Instalado a través de OAuth en el área de trabajo
Inicio rápido Nuevos proyectos creados a través de la CLI para desarrolladores de Teams Nuevos proyectos creados a través de la CLI de Slack.
Manifiesto de la aplicación Cree y registre un agente y su manifiesto de aplicación con la CLI para desarrolladores de Teams. Creado a través de JSON, YAML o la página de administración de aplicaciones.
Punto de conexión de mensajería Establecer en el portal para desarrolladores de Teams, la configuración de bots o en el recurso de Servicio de Bot de Azure AI. Se establece en el manifiesto de la aplicación de Slack.
Autenticación de aplicaciones El registro de aplicaciones de Entra se autoriza durante la instalación de aplicaciones de Teams. El SDK de Teams captura el token de la aplicación Entra internamente al enviar mensajes. Las características principales de la aplicación, como la mensajería, usan este tipo de autenticación internamente dentro del SDK. La aplicación almacena el token del bot de Slack después de que el usuario autoriza los ámbitos delegados de la aplicación (por ejemplo,incoming-webhook,commands). Las características principales de la aplicación, como la mensajería, usan este tipo de autenticación internamente dentro del SDK.
Autenticación de usuario para API de REST Los tokens de Entra del usuario se pueden obtener mediante el SSO de Teams. Las API de REST de Graph están integradas en el SDK de Teams. Los tokens se almacenan y actualizan mediante el servicio de token de bot de Azure. Los tokens de Slack del usuario se pueden obtener mediante OAuth 2.0. Las API REST de Slack están integradas en Slack Bolt. La aplicación debe almacenar y actualizar los tokens.
Autenticación con servicios externos Obtener tokens de acceso de usuario para servicios externos mediante OAuth 2.0. Los tokens se almacenan y actualizan mediante el servicio de token de bot de Azure. Los usuarios se autentican en servicios externos con OAuth 2.0, tal vez iniciados a través del enlace de cuenta (ver más abajo). La aplicación debe almacenar y actualizar los tokens.
Vinculación de cuentas Activity los eventos incluyen Activity.from.id, que es el id. de objeto de AAD del usuario. Si autentica el servicio externo con OAuth 2.0, estas cuentas se enlazan implícitamente a través del servicio de token de Azure, pero también puede seguir un flujo similar al recomendado por Slack. Slack recomienda seguir su guía Enlazar cuentas entre servicios .
Tarjetas Elementos de interfaz de usuario enriquecidos en mensajes que usan tarjetas adaptativas. Elementos de interfaz de usuario enriquecidos en mensajes mediante Block Kit.
Files Los Files se pueden adjuntar o descargar mediante las API de SharePoint o OneDrive Graph. Los Files se pueden adjuntar o descargar a través de las API de archivos de Slack.
Mensajes privados en conversaciones de grupo Mensajes dirigidos Mensajes efímeros.
Comandos de barra diagonal Comandos de barra diagonal, declarados en el manifiesto de la aplicación y hechos reconocibles a través de un menú Autocompletar. Los comandos se pueden enviar como mensajes dirigidos privados o visibles para todos los usuarios en una conversación a través de @mention. Los comandos se envían como mensajes: escuche los comandos con un app.message controlador, ya sea a través de app.message('/command') o app.message(regexp). Slack Bolt tiene un controlador dedicado app.command para comandos en el manifiesto de la aplicación Slack. Los comandos de barra diagonal no se muestran a otros usuarios en contextos de colaboración.
Flujos de trabajo Teams se integra con Power Automate para flujos de trabajo. Los flujos de trabajo no son un componente del SDK de Teams. Los flujos de trabajo de Slack están integrados con Slack Bolt.
Cuadros de diálogo de la interfaz de usuario Las tarjetas adaptables pueden incluir acciones que abren cuadros de diálogo de interfaz de usuario con un sitio web insertado u otra tarjeta adaptable. Los cuadros de diálogo se deben abrir mediante una acción de tarjeta adaptable y, por lo tanto, no se pueden abrir directamente mediante un comando de barra diagonal. Los modales de la interfaz de usuario del kit de bloques se pueden abrir mediante comandos de barra diagonal (mediante client.views.open) o acciones de kit de bloques.
Estrategia de IA Teams tiene características nativas de IA únicas para cosas como comentarios de los usuarios, etiquetas generadas por IA, sugerencias de avisos, streaming y citas. También contamos con una clase opcional ChatPrompt para simplificar la integración de LLM en el bot. Aprovechar la búsqueda fundamentada a través de la Microsoft 365 Copilot Retrieval Graph API. Las características de IA suelen estar diseñadas para su uso en cualquier tipo de conversación. Slack tiene una clase dedicada Assistant para las interacciones de IA en una vista de panel lateral de agente dedicada, que difiere de la estrategia de Teams de usar los patrones de interacción de bots existentes. Todavía puede usar IA en otros tipos de conversación mediante API de bot estándar. Puede usar la API de acceso a datos de Slack para la búsqueda fundamentada.
Comentarios de los usuarios de IA Los botones de comentarios de los usuarios se representan de forma nativa en Teams con API dedicadas para manejar los comentarios. Después de que el usuario da comentarios positivos o negativos, se abre un modal donde se puede capturar información adicional (por ejemplo, respuesta de texto sin formato). Slack utiliza un tipo de elemento Block Kit dedicado feedback_buttons y app.action('feedback') para adjuntar los comentarios de los usuarios (positivos frente a negativos) a los mensajes.

Registrar un agente de Teams

En primer lugar, complete el inicio rápido para registrar un nuevo agente de Teams, de modo que pueda usarlo desde Teams tan pronto como haya agregado la implementación del SDK de Teams a su aplicación existente.

Instalar el SDK de Teams

Instale el SDK de Teams en su proyecto de Slack Bolt:

npm install @microsoft/teams.apps

Copiar configuración de autenticación

Copie la configuración del .env archivo que la CLI para desarrolladores de Teams creó en la aplicación de inicio rápido en la implementación de Slack Bolt. Estas configuraciones son credenciales para autenticar una aplicación SDK de Teams para que pueda comunicarse con Teams.

Inicializar el tiempo de ejecución

Agregue o reemplace código en la implementación para iniciar el tiempo de ejecución de la aplicación del SDK de Teams con la App clase. Esto es equivalente a la clase de App Slack Bolt.

import { App } from '@microsoft/teams.apps';

const app = new App();

app.start(process.env.PORT || 3978).catch(console.error);

Agregar controladores de mensajes

En Slack, hay controladores de mensajes para eventos con diferentes subtipos (por ejemplo, subtipo no definido es un mensaje normal, event.subtype == 'file_share' es un mensaje de recurso compartido de archivos, etc.). En Teams, hay diferentes Activity controladores para diferentes tipos de eventos que se enumeran a través de la ActivityTypes enumeración (por ejemplo, app.activity(ActivityTypes.Message)), y algunos Activity tipos tienen API adaptadas dentro del SDK (por ejemplo, app.message). Estos conceptos son más o menos similares, aunque las convenciones de nomenclatura y la sintaxis difieren.

// triggers when user sends "hi" or "@bot hi"
app.message("hi", async ({ send, activity }) => {
    await send(`Hello, ${activity.from.name}!`);
});
// listen for ANY message to be received
app.on('message', async ({ send, activity }) => {
    // echo back users request
    await send(`you said: ${activity.text}`);
});

Convertir el uso de Block Kit en tarjetas adaptables

Para incluir una interfaz de usuario enriquecida en los mensajes enviados por el agente, las tarjetas adaptables de Teams son equivalentes al kit de bloques de Slack.

import { Card, TextBlock } from '@microsoft/teams.cards';

app.message('/card', async ({ send }) => {
    await send(
        new Card(new TextBlock('Hello, world!', { wrap: true, isSubtle: false }))
            .withOptions({
                width: 'Full',
            })
    );
});

Implementar la autenticación de usuario

Hay dos tipos principales de autenticación de usuario para Teams y Slack: autenticación para las API REST de Slack & Graph y autenticación para servicios externos. Echemos un vistazo a cada uno de estos a su vez.

API de REST delegadas por el usuario

En Slack, si desea usar las API de REST de Slack que requieren ámbitos delegados por el usuario, debe implementar un flujo de instalación de OAuth 2.0 en la aplicación para obtener y almacenar tokens de usuario de Slack, incluso si la aplicación ya la ha instalado otro usuario. En Teams, puede aprovechar el SSO de Teams para obtener tokens de Entra de usuario para llamar a las API REST de Graph. El SDK de Teams se integra con el SSO de Teams y el servicio de tokens de bot de Azure para administrar la adquisición de tokens, el almacenamiento y la actualización automáticamente.

Primero, siga las instrucciones de la guía de SSO de Teams. A continuación, configure la autenticación en el código.

const app = new App({
    // ... rest of App config
    oauth: {
        // The key here should match the OAuth Connection setting
        // defined in your Azure Bot resource.
        defaultConnectionName: 'graph',
    },
});

app.message('me', async ({ signin, userGraph, send }) => {
    if (!await signin()) {
        return;
    }
    const me = await userGraph.call(endpoints.me.get);
    await send(JSON.stringify(me));
});

Autenticación de usuario para servicios externos

En Slack, puede acceder a servicios externos implementando un flujo de enlace de cuenta mediante OAuth 2.0 como se documenta aquí. En Teams, puede acceder a servicios externos implementando un flujo de OAuth 2.0 con el servicio de token de bot de Azure que gestiona automáticamente la adquisición, el almacenamiento y la actualización de tokens.

En primer lugar, configure la configuración de la conexión de OAuth 2.0 en Azure Portal para el recurso de Azure Bot.

Captura de pantalla que muestra la configuración de conexión de OAuth personalizada de Azure Bot.

A continuación, agregue el código de autenticación a la aplicación para obtener el token de usuario pertinente y llamar al servicio externo.

import
{ App } from '@microsoft/teams.apps';

const app = new App({
    // ... rest of App config
    oauth: {
        // The key here should match the OAuth Connection setting
        // defined in your Azure Bot resource.
        defaultConnectionName: 'custom',
    },
});

app.message('me', async ({ activity, signin, token, send }) => {
    // In production, it is probably better to implement a local cache.
    // (e.g. \`activity.from.id\` <-> token).
    // Otherwise this triggers an API call to Azure Token Service on every inbound message.
    if (!await signin()) {
        return;
    }

    // Call external API
    const response = await fetch('https://example.com/api/helloworld', {
        method: 'POST',
        headers: {
            "Authorization": token,
        },
    });
    const result = await response.json();
    await send(JSON.stringify(result));
});