Preview release of the Node.js Bot Builder v4 SDK for Microsoft Teams

Microsoft Teams team

We’re excited to announce the preview release of the Node.js Teams Bot Builder v4 SDK. This has consistently been a top ask from our bot builders and we’re very happy to begin expanding our support for bots built on Bot Framework to include the newest version. This preview release is just the beginning; over the next few months we’ll be adding new documentation, samples and releasing our SDKs for both .NET and Node.js.

A brief introduction to Bot Framework v4 for Node.js

First and foremost, its important to realize that everything you can do in Bot Framework v4, you can do in v3 (and vice-versa), it’s just different. If you haven’t worked with Bot Framework v4 I highly recommend reading through the Concept section of their documentation. You’ll get a great introduction to the platform, how it is structured, and what pieces you’ll need to focus on as you design your bot.

The core concept underlying Bot Framework is the idea of a turn, which represents a complete question-and-response interaction with your bot. The below diagram shows a typical interaction with your bot. You receive an HTTP Post message containing JSON from the client. The Adapter creates an Activity object, initiates the OnTurn pipeline and passes the Activity to any middleware you’ve registered. After performing it’s logic, the middleware passes the Activity to your bot to perform your OnTurn logic, and if necessary you read/write to your state through a state property accessor. Once your logic finishes the Activity is handed back to the middleware for any final processing, and finally your response is returned to the client.

Overview of the Microsoft Teams Bot Builder SDK for Node.js

Our SDK extends the core Bot Builder SDK with Microsoft Teams specific functionality allowing you to create a rich experiences for your users. In addition to adding Teams specific extensions to the Bot Builder libraries (TeamsActivityProcessor, TeamsAdapter and TeamsConnectorClient), we add four middleware classes and a Teams-specific conversation state.

  • TeamsMiddleware – This is the core middleware that creates a TeamContext object which adds Teams specific information to the Activity.
  • DropChannelActivitiesMiddleware & DropChatActivitiesMiddleware – Both allow you to restrict interactions to a particular kind of channel. For example, if your bot doesn’t support one-on-one chat you can drop all chat activities.
  • DropNonTeamsActivitiesMiddleware – Allows you to short-circuit the OnTurn pipeline if the activity didn’t originate from Teams
  • TeamSpecificConversationState – This allows you to make use of a state storage accessor that is scoped across an entire Team (two separate interactions with your bot from two members of the same Team can access the same bot state)

Getting Started with the Microsoft Teams Bot Builder SDK for Node.js

We’ll be using the EchoBot scaffold provided by Bot Framework. You can find the full quickstart here.

  1. Open a terminal or elevated command prompt
  2. Change to a clean working directory
  3. Run the following commands

npm install -g yo generator-botbuilder

yo botbuilder

Yeoman will prompt you for some information, make sure you choose TypeScript for the language, and the Echo template.

Next, you’ll need to install the Microsoft Teams Bot Builder SDK for Node.js package.

npm install botbuilder-teams@4.0.0-beta1

In the index.ts file we’ll import the teams SDK, update the adapter constant to use a TeamsAdapter, and wire up the TeamsMiddleware:

import * as teams from ‘botbuilder’

const adapter = new teams.TeamsAdapter({
    appId: endpointConfig.appId || process.env.microsoftAppID,
    appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword,
});
adapter.use(new teams.TeamsMiddleware());
In the bot.ts file we’ll add the import statement and modify the onTurn method to add some Teams-specific information to the response based on what the user says to the bot.
import { ActivityTypes, TurnContext, Activity } from ‘botbuilder’;
import * as teams from ‘botbuilder-teams’;
export class MyBot {
    private readonly activityProcessor = new teams.TeamsActivityProcessor();
    constructor(){
        this.setupHandlers();
    }
    public async onTurn(turnContext: TurnContext) {
        if (turnContext.activity.type === ActivityTypes.Message) {
            await this.activityProcessor.processIncomingActivity(turnContext);
        } else {
            await turnContext.sendActivity(`[${ turnContext.activity.type } event detected]`);
        }
    }
    private setupHandlers () {
        this.activityProcessor.messageActivityHandler = {
            onMessage: async (ctx: TurnContext) => {
                const teamsContext = teams.TeamsContext.from(ctx);
                const text = teamsContext.getActivityTextWithoutMentions();
                const adapter = ctx.adapter as teams.TeamsAdapter;
                switch (text.toLowerCase()) {
                    case ‘reply-chain’:
                        await adapter.createReplyChain(ctx, [{ text: ‘New reply chain’ }]);
                        break;
                    case ‘1:1’:
                        // create 1:1 conversation
                        const tenantId = teamsContext.tenant.id;
                        const ref = TurnContext.getConversationReference(ctx.activity);
                        await adapter.createTeamsConversation(ref, tenantId, async (newCtx) => {
                            await newCtx.sendActivity(`Hi (in private)`);
                        });
                        break;
                    case ‘members’:
                        const members = await adapter.getConversationMembers(ctx);
                        const actMembers = await adapter.getActivityMembers(ctx);
                        await ctx.sendActivity({
                            textFormat: ‘xml’,
                            text: `
                                <b>Activity Members</b></br>
                                <pre>${JSON.stringify(actMembers, null, 2)}</pre>
                                <b>Conversation Members</b></br>
                                <pre>${JSON.stringify(members, null, 2)}</pre>
                        `});
                        break;
                    case ‘team-info’:
                        const teamId = teamsContext.team.id;
                        const chList = await teamsContext.teamsConnectorClient.teams.fetchChannelList(teamId);
                        const tmDetails = await teamsContext.teamsConnectorClient.teams.fetchTeamDetails(teamId);
                        await ctx.sendActivity({ textFormat: ‘xml’, text: `<pre>${JSON.stringify(chList, null, 2)}</pre>`});
                        await ctx.sendActivity({ textFormat: ‘xml’, text: `<pre>${JSON.stringify(tmDetails, null, 2)}</pre>`});
                        break;
                    default:
                        let activity: Partial<Activity> = {
                            textFormat: ‘xml’,
                            text: `You said “${ ctx.activity.text }”`
                        };
                        activity = teams.TeamsContext.notifyUser(activity as Activity);
                        await ctx.sendActivity(activity);
                }
            }
        };
    }
}
To deploy and test your bot, you can use App Studio to register a new bot with Bot Framework and create a manifest file. Once you’ve got a bot Id and Password you’ll need to add them to the <botname>.bot file, as well as update the endpoint (if you’re working locally you’ll need to use a tunneling service like ngrok to get a publicly facing URL to use). You can find detailed instructions on how to do this in our documentation.

Additional resources

Feedback usabilla icon