Diretrizes de migração do Azure Bot Framework SDK para SDK de Agentes do Microsoft 365 para Node.js

Este artigo descreve as alterações necessárias para migrar do SDK do Bot Framework para Node.js.

Pré-requisitos

  • Node.js versão 20 ou superior
  • Projeto do SDK do Bot Framework existente
  • Azure Serviço de Bot recurso (permanece inalterado durante a migração)

Alterações no Código do SDK do NodeJS

As alterações nesta seção ocorrem devido a diferenças entre o SDK Azure Bot Framework e o SDK de Agentes do Microsoft 365 JavaScript .

Recursos do Azure

Seus recursos do Azure permanecem inalterados. Você precisa referenciar as propriedades appsettings de MicrosoftAppType, MicrosoftAppId, MicrosoftAppPassword e MicrosoftAppTenantId. No entanto, esses nomes de configuração não são mais usados e podem ser excluídos posteriormente. Saiba mais sobre configuração do ambiente

Primeiras etapas

Aplique as alterações a seguir primeiro para resolver a maioria das diferenças. Você ainda precisará depurar e verificar se há outras diferenças depois de aplicar essas alterações.

Atualizar dependências de pacote

Essa alteração não obtém todos os namespaces necessários resolvidos, mas abrange a maior parte deles.

Cenário SDK do Bot Framework SDK de Agentes
Hospedagem principal botbuilder @microsoft/agents-hosting
Esquema da atividade botframework-schema @microsoft/agents-activity
Dialogs botbuilder-dialogs @microsoft/agents-hosting-dialogs
Azure Cosmos DB botbuilder-azure @microsoft/agents-hosting-storage-cosmos
Armazenamento de Blobs do Azure botbuilder-azure-blobs @microsoft/agents-hosting-storage-blob
Utilitários de servidor expresso Configuração manual @microsoft/agents-hosting-express

Bots usando o Teams

Se o bot usar o Teams, adicione uma dependência de pacote para @microsoft/agents-hosting-extensions-teams

Atualizar importações/exigir

Use localizar e substituir para fazer as seguintes alterações:

Bot Framework SDK de Agentes
require('botframework-schema'); require('@microsoft/agents-activity')
require('botbuilder'); require('@microsoft/agents-hosting')
require('botbuilder-dialogs'); require('@microsoft/agents-hosting-dialogs')

Classe de Atividade do SDK de Agentes

O pacote @microsoft/agents-activity inclui a Classe de atividade para executar a análise com base no zod. Você pode analisar e validar suas atividades personalizadas do JSON com Activity.fromJson() ou de objetos JavaScript literais com Activity.fromObject().

Além disso, a classe Activity centraliza todas as operações relacionadas ao conteúdo da atividade, como getConversationReference. Os métodos na tabela a seguir foram movidos de TurnContext e agora operam sobre a instância de atividade atual:

Método estático do Bot Framework Método de instância do SDK de Agentes
TurnContext.applyConversationReference activity.applyConversationReference
TurnContext.getConversationReference activity.getConversationReference
TurnContext.getReplyConversationReference activity.getReplyConversationReference
TurnContext.removeRecipientMention activity.removeRecipientMention
TurnContext.getMentions activity.getMentions
TurnContext.removeMentionText activity.removeMentionText

Inicialização e Configuração

O sistema de configuração do SDK de Agentes substitui a classe ConfigurationBotFrameworkAuthentication pela interface AuthConfiguration.

Para carregar a configuração do arquivo padrão .env usa loadAuthConfigFromEnv.

Importante

As variáveis de configuração são descritas em Configurar autenticação em JavaScript.

Configuração do Ambiente

Crie um arquivo .env com as seguintes variáveis:

# Required for Azure Bot Service
clientId=your-app-id
clientSecret=your-app-secret  
tenantId=your-tenant-id

# Optional - for local debugging
PORT=3978
DEBUG=true

Observação de Migração: atualize os nomes das variáveis de ambiente, conforme mostrado na tabela a seguir:

SDK do Bot Framework SDK de Agentes
MicrosoftAppId clientId
MicrosoftAppPassword clientSecret
MicrosoftAppTenantId tenantId

Autenticação e segurança

Quando o SDK do Bot Framework autoriza solicitações de entrada, ele inclui tokens de autorização JWT (Token Web JSON) na pilha. O SDK de agentes não. Ao usar um runtime do servidor Web, como o Express, você precisa configurar um middleware JWT para autorizar solicitações de entrada com base no Token de portador JWT, o SDK dos Agentes fornece o método authorizeJWT(AuthConfiguration).

Middleware JWT (Necessário para produção):

import { authorizeJWT, loadAuthConfigFromEnv } from '@microsoft/agents-hosting'

const authConfig = loadAuthConfigFromEnv()
server.use(authorizeJWT(authConfig))

Desenvolvimento Local:

Para depuração local, a validação JWT pode ser desabilitada:

// Only for local development - NEVER in production
if (process.env.NODE_ENV === 'development') {
    // JWT validation disabled for local testing
} else {
    server.use(authorizeJWT(authConfig))
}

Opções de Instalação do Servidor

O SDK de Agentes fornece duas abordagens para configurar o servidor:

Usar o método startServer

Utilize essa abordagem simplificada para novos projetos quando desejar uma configuração mínima e não precisar de middleware personalizado.

Atualize o código de inicialização de botbuilder:

const { EchoBot } = require('./bot');
const {
    CloudAdapter,
    ConfigurationBotFrameworkAuthentication
} = require('botbuilder');
const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(process.env);
const adapter = new CloudAdapter(botFrameworkAuthentication);
const myBot = new EchoBot();
const server = express();
server.use(express.json());
server.post('/api/messages', async (req, res) => 
    await adapter.process(req, res, (context) => 
      myBot.run(context));
);

Para hospedagem de agentes com startServer():

const { EchoBot } = require('./bot');
const { startServer } = require('@microsoft/agents-hosting-express')
startServer(new EchoBot());

Configuração manual do Express

Use essa abordagem ao migrar bots existentes, precisar de middleware personalizado, desejar controle total sobre a configuração do Express

const { EchoBot } = require('./bot');
const {
    CloudAdapter,
    loadAuthConfigFromEnv, // Update
    authorizeJWT // Update
} = require('@microsoft/agents-hosting'); // Update
const authConfig = loadAuthConfigFromEnv(); // Update
const adapter = new CloudAdapter(authConfig); // Update
const myBot = new EchoBot();
const server = express();
server.use(express.json());
server.use(authorizeJWT(authConfig)); // Update
server.post('/api/messages', async (req, res) => 
    await adapter.process(req, res, (context) => 
      myBot.run(context));
);

const port = process.env.PORT || 3978;
server.listen(port, () => {
    console.log(`Server listening on port ${port}`);
}).on('error', (err) => {
    console.error('Server failed to start:', err);
    process.exit(1);
});

Suporte a ActivityHandler

A maioria dos bots criados com o SDK do Bot Framework baseia-se na classe base botbuilder-core.ActivityHandler.

O SDK de Agentes fornece um agents-hosting.ActivityHandler compatível que mantém a mesma superfície de API para facilitar a migração.

Principais diferenças

Algumas das principais diferenças entre o SDK do Bot Framework e o SDK de Agentes incluem:

Parâmetros do Manipulador:

SDK Tipo de Manipulador
SDK do Bot Framework BotHandler
SDK de Agentes AgentHandler

Métodos Adicionais no SDK de Agentes:

Método Description
onMessageDelete Manipula atividades de exclusão de mensagens
onMessageUpdate Manipula as atividades de atualização de mensagens
onSignInInvoke Manipula as atividades de invocação de entrada

Métodos Ausentes no SDK de Agentes:

Método Motivo
onCommand Não há suporte para atividades de comando
onCommandResult Não há suporte para atividades de resultado de comando
onEvent Tratamento de eventos genéricos (tipos de evento específicos como onTokenResponseEvent ainda têm suporte)
onTokenResponseEvent Eventos de resposta do token OAuth

Alterações de Assinatura de Método:

Todos os métodos de manipulador retornam ActivityHandler em vez de this encadeamento do método. As funções de manipulador usam o tipo AgentHandler, que tem a mesma assinatura que BotHandler

Exemplo de Migração:

SDK do Bot Framework:

const { ActivityHandler } = require('botbuilder');

class MyBot extends ActivityHandler {
    constructor() {
        super();
        this.onMessage(async (context, next) => {
            await context.sendActivity('Hello!');
            await next();
        });
    }
}

A migração é em grande parte simples, com a principal alteração sendo a instrução de importação e o tipo de manipulador. A maioria dos bots baseados em ActivityHandlerdeve funcionar com modificações mínimas.

Importante

O valor ActivityHandler foi preterido em favor da nova classe AgentApplication

Migrando de ActivityHandler para AgentApplication

Embora ActivityHandler tenha suporte para compatibilidade com versões anteriores, a abordagem recomendada é usar AgentApplication:

Usando ActivityHandler:

import { ActivityHandler } from '@microsoft/agents-hosting'

class MyBot extends ActivityHandler {
    constructor() {
        super()
        this.onMessage(async (context, next) => {
            await context.sendActivity('Hello!')
            await next()
        })
        
        this.onMembersAdded(async (context, next) => {
            await context.sendActivity('Welcome!')
            await next()
        })
    }
}

Principais Diferenças

A tabela a seguir descreve as principais diferenças de recursos entre ActivityHandler e AgentApplication:

Característica ActivityHandler AgentApplication
Gerenciamento de Estado Gerenciamento de estado manual necessário Gerenciamento de estado interno fornecido
Manipulação de eventos Manipuladores de eventos genéricos (por exemplo, onMembersAdded) Manipuladores de eventos mais específicos (por exemplo, membersAdded)
Próxima Função Os manipuladores exigem a chamada next() Os manipuladores não exigem as chamadas next()
Armazenamento Configuração manual de armazenamento Suporte de armazenamento interno com persistência automática de estado

Padrões Comuns de Migração

Alguns padrões comuns de migração são:

Echo Bot Simples

Bot Framework

const { ActivityHandler } = require('botbuilder')

class EchoBot extends ActivityHandler {
    constructor() {
        super()
        this.onMessage(async (context, next) => {
            await context.sendActivity(`You said: ${context.activity.text}`)
            await next()
        })
    }
}

Gerenciamento de estado

Usando AgentApplication:

import { AgentApplication, MemoryStorage } from '@microsoft/agents-hosting'

const agent = new AgentApplication({
    storage: new MemoryStorage()
})

agent.onMessage('/count', async (context, state) => {
    const count = state.conversation.count ?? 0
    state.conversation.count = count + 1
    await context.sendActivity(`Count: ${state.conversation.count}`)
})

Herdando do AgentApplication

Para cenários mais complexos, você pode criar uma classe que herda de AgentApplication:

import { AgentApplication, MemoryStorage, MessageFactory } from '@microsoft/agents-hosting'

class MyAgent extends AgentApplication {
    constructor() {
        super({
            storage: new MemoryStorage()
        })
        this.setupRoutes()
    }
    
    setupRoutes() {
        this.onMessage('/help', this.handleHelp)
        this.onMessage('/status', this.handleStatus)
        this.onMessage('/reset', this.handleReset)
        
        this.onActivity('message', this.handleDefault)
        this.onConversationUpdate('membersAdded', this.handleWelcome)
    }
    
    handleHelp = async (context, state) => {
        const helpText = `
                Available commands:
                - /help - Show this help message
                - /status - Show current status
                - /reset - Reset conversation state
        `
        await context.sendActivity(MessageFactory.text(helpText))
    }
    
    handleStatus = async (context, state) => {
        const messageCount = state.conversation.messageCount ?? 0
        await context.sendActivity(`Messages processed: ${messageCount}`)
    }
    
    handleReset = async (context, state) => {
        state.deleteConversationState()
        await context.sendActivity('Conversation state has been reset.')
    }
    
    handleWelcome = async (context, state) => {
        const welcomeText = 'Welcome! Type /help to see available commands.'
        await context.sendActivity(MessageFactory.text(welcomeText))
    }
    
    handleDefault = async (context, state) => {
        // Increment message counter
        const messageCount = (state.conversation.messageCount ?? 0) + 1
        state.conversation.messageCount = messageCount
        
        const replyText = `Echo: ${context.activity.text} (Message #${messageCount})`
        await context.sendActivity(MessageFactory.text(replyText))
    }
}

export default new MyAgent()

Benefícios desse padrão

Benefício Description
Melhor organização Métodos separados para manipuladores diferentes
Reutilização Pode ser facilmente estendido ou herdado ainda mais
Testabilidade Métodos individuais podem ser testados por unidade
Maintainability Estrutura de código mais limpa para bots complexos
Funções de seta Associar automaticamente o this contexto sem precisar .bind()