Indicazioni per la migrazione da Azure Bot Framework SDK a Managed Disks per Node.js

Questo articolo descrive le modifiche necessarie per migrare da Bot Framework SDK per Node.js.

Prerequisiti

  • Node.js versione 20 o superiore
  • Progetto Bot Framework SDK esistente
  • Azure servizio Bot risorsa (rimane invariata durante la migrazione)

Modifiche al codice dell'SDK NodeJS

Le modifiche in questa sezione sono dovute a differenze tra Azure Bot Framework SDK e Managed Disks JavaScript .

Risorse di Azure

Le risorse Azure rimangono invariate. È necessario fare riferimento alle proprietà di appsettings per MicrosoftAppType, MicrosoftAppId, MicrosoftAppPassworde MicrosoftAppTenantId. Tuttavia, questi nomi di impostazione non vengono più usati e possono essere eliminati in un secondo momento. Per saperne di più sulla configurazione dell'ambiente

Passaggi iniziali

Applicare prima le seguenti modifiche per risolvere la maggior parte delle differenze. Sarà comunque necessario eseguire il debug e verificare la presenza di altre differenze dopo aver applicato queste modifiche.

Aggiornare le dipendenze dei pacchetti

Questa modifica non risolve tutti gli spazi dei nomi richiesti, ma ne copre la maggior parte.

Scenario Bot Framework SDK SDK per agenti
Hosting principale botbuilder @microsoft/agents-hosting
Schema delle attività botframework-schema @microsoft/agents-activity
Dialogs botbuilder-dialogs @microsoft/agents-hosting-dialogs
Azure Cosmos DB, un servizio di database distribuito globale di Microsoft botbuilder-azure @microsoft/agents-hosting-storage-cosmos
Blob Storage di Azure botbuilder-azure-blobs @microsoft/agents-hosting-storage-blob
Utilità del server espresso Configurazione manuale @microsoft/agents-hosting-express

Bot che utilizzano Teams

Se il bot usa Teams, aggiungere una dipendenza del pacchetto per @microsoft/agents-hosting-extensions-teams

Aggiornare le importazioni/richiedere

Usare Trova e sostituisci per apportare le seguenti modifiche:

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

Agenti SDK Classe di attività

Il pacchetto @microsoft/agents-activity include la classe Activity per eseguire il parsing basato su zod. È possibile analizzare e validare le attività personalizzate da JSON con Activity.fromJson() o da oggetti JavaScript letterali con Activity.fromObject().

Inoltre, la classe Activity centralizza tutte le operazioni relative al carico utile dell'attività, come ad esempio getConversationReference. I metodi della tabella seguente sono stati spostati da TurnContext e ora operano sull'istanza dell'attività corrente:

Metodo statico del Bot Framework Metodo di istanza dell'SDK Agenti
TurnContext.applyConversationReference activity.applyConversationReference
TurnContext.getConversationReference activity.getConversationReference
TurnContext.getReplyConversationReference activity.getReplyConversationReference
TurnContext.removeRecipientMention activity.removeRecipientMention
TurnContext.getMentions activity.getMentions
TurnContext.removeMentionText activity.removeMentionText

Avvio e configurazione

Il sistema di configurazione del SDK Agents sostituisce la classe ConfigurationBotFrameworkAuthentication con l'interfaccia AuthConfiguration.

Per caricare la configurazione dal file predefinito .env si usa loadAuthConfigFromEnv.

Important

Le variabili di configurazione sono descritte in Configurare l'autenticazione in JavaScript.

Configurazione dell'ambiente

Creare un file .env con le seguenti variabili:

# 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

Nota di migrazione: Aggiornare i nomi delle variabili d'ambiente come indicato nella tabella seguente:

Bot Framework SDK SDK per agenti
MicrosoftAppId clientId
MicrosoftAppPassword clientSecret
MicrosoftAppTenantId tenantId

Autenticazione e sicurezza

Quando Bot Framework SDK autorizza le richieste in entrata, include nello stack i token di autorizzazione JSON Web Token (JWT). Agents SDK non funziona. Quando si utilizza un runtime di un server web come express, è necessario configurare un middleware JWT per autorizzare le richieste in entrata in base al token JWT Bearer; l'SDK Agents fornisce il metodo authorizeJWT(AuthConfiguration).

Middleware JWT (richiesto per la produzione):

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

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

Sviluppo locale:

Per il debug locale, la convalida JWT può essere disabilitata:

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

Opzioni di impostazione del server

L'SDK Agents offre due approcci per la configurazione del server:

Utilizzare il metodo startServer

Utilizza questo approccio semplificato per i nuovi progetti quando desiderate una configurazione minima e non hai bisogno di middleware personalizzato.

Aggiornare il codice di inizializzazione da 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));
);

Agli agenti-hosting con startServer():

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

Impostazione manuale di Express

Utilizzare questo approccio quando si migrano bot esistenti, si necessita di middleware personalizzato, si vuole il pieno controllo della configurazione di 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);
});

Supporto per ActivityHandler

La maggior parte dei bot creati con il Bot Framework SDK si basa sulla classe base botbuilder-core.ActivityHandler.

L'SDK Agents fornisce un agents-hosting.ActivityHandler compatibile che mantiene la stessa superficie API per facilitare la migrazione.

Differenze principali

Alcune differenze chiave tra l'SDK del Bot Framework e l'SDK degli Agenti includono:

Parametri del gestore:

SDK Tipo di gestore
Bot Framework SDK BotHandler
SDK per agenti AgentHandler

Metodi aggiuntivi nell'SDK Agenti:

Metodo Description
onMessageDelete Gestisce le attività di cancellazione dei messaggi
onMessageUpdate Gestisce le attività di aggiornamento dei messaggi
onSignInInvoke Gestisce le attività di invocazione dell'accesso

Metodi mancanti nell'SDK Agenti:

Metodo Motivo
onCommand Le attività di comando non sono supportate
onCommandResult Le attività di risultato dei comandi non sono supportate
onEvent Gestione di eventi generici (sono ancora supportati tipi di eventi specifici come onTokenResponseEvent )
onTokenResponseEvent Eventi di risposta del token OAuth

Modifiche alla firma del metodo:

Tutti i metodi dei gestori restituiscono ActivityHandler invece di this per il concatenamento dei metodi. Le funzioni di gestione utilizzano il tipo AgentHandler, che ha la stessa firma di BotHandler

Esempio di migrazione:

Bot Framework SDK:

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

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

La migrazione è per lo più semplice, con la modifica principale della dichiarazione di importazione e del tipo di gestore. La maggior parte dei bot esistenti basati su ActivityHandlerdovrebbe funzionare con modifiche minime.

Important

La classe ActivityHandler è stata deprecata a favore della nuova classe AgentApplication

Migrazione da ActivityHandler a AgentApplication

Sebbene ActivityHandler sia supportato per la retrocompatibilità, l'approccio consigliato è quello di utilizzare AgentApplication:

Utilizzo di 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()
        })
    }
}

Differenze chiave

La tabella seguente descrive le principali differenze di funzionalità tra ActivityHandler e AgentApplication:

Caratteristica / Funzionalità ActivityHandler AgentApplication
Gestione dello Stato È necessaria la gestione manuale dello stato Gestione degli stati incorporata
Gestione di eventi Gestori di eventi generici (ad esempio, onMembersAdded) Gestori di eventi più specifici (ad esempio, membersAdded)
Funzione successiva I gestori richiedono di chiamare next() I gestori non richiedono di chiamare next()
Spazio di archiviazione Configurazione manuale dell'archiviazione Supporto di archiviazione integrato con persistenza automatica dello stato

Modelli di migrazione comuni

Alcuni modelli di migrazione comuni sono:

Bot Eco semplice

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()
        })
    }
}

Gestione dello stato

Utilizzo di 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}`)
})

Ereditando da AgentApplication

Per scenari più complessi, è possibile creare una classe che eredita da 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()

Vantaggi di questo modello

Benefit Description
Migliore organizzazione Metodi separati per gestori diversi
Riutilizzabilità Può essere facilmente esteso o ereditato ulteriormente
Testabilità I singoli metodi possono essere testati unitariamente
Manutenibilità Struttura del codice più pulita per bot complessi
Funzioni della freccia Legare automaticamente il contesto di this senza bisogno di .bind()