Managing Versions in Bot Framework

In Artificial Intelligence by Christian HissibiniLeave a Comment

Versioning a live bot is a little trickier. You want to get users onto the new bot as quickly as possible, but you probably don’t want to interrupt the current flow of a user already in the middle of a dialog. If nothing else, when you version your bot, you need to handle the fact that a user in the middle of a dialog might be returning to a dialog step that doesn’t exist, or a dialog that’s changed profoundly, meaning the message the user sent might not make sense in the flow you deployed.

Reloading an older version

If you do want to transition the user, you will need to pay a little bit of attention to how you update your bot. In theory, you could do this on a dialog by dialog basis, but the code becomes trickier as you need to figure out where the user is, and swap out the dialog. I find it much easier to simply swap out the entire bot. To help manage this, I’ll put the bot, and its associated dialogs, into a folder. When it comes time to update it, I’ll copy the entire folder structure, update the copy, and then update app.js to call the updated (new) bot.

When you need to send a user to the old bot, you simply update the library property of the session, which sets the bot that will run for the incoming message. In the code snippet below, I have both an updated and original bot in the same file for simplicity’s sake. I hope you can see from here how you would implement this with multiple folders.

In the sample below, I’m going to transition the user once their current conversation completes. You could, if you so desire, update this code to always reset the conversation, with a message of course, which would cause the user to be rerouted to the new bot. Also, the code could be streamlined a little bit, but breaking it apart like I’ve done makes it (I think) a little easier to explain with comments.

const connector = new builder.ChatConnector();
const bot = new builder.UniversalBot(
    // this is the updated bot
    connector,
    [
        (session) => {
            builder.Prompts.text(session, 'What is your name?');
        },
        (session, results) => {
            session.endConversation(`Hello, ${results.response}, from the updated bot`);
        }
    ]
);
// set a version number using duck typing
bot.version = 2;

const getOriginalBot = (connector) =>{
    // this will return the original bot
    const originalBot = new builder.UniversalBot(
        connector,
        [
            (session) => {
                builder.Prompts.text(session, 'What is your name?');
            },
            (session, results) => {
                session.endConversation(`Hello, ${results.response}, from the original bot`);
            }
        ]
    );
    // set a version number by using duck typing
    originalBot.version = 1;
    return originalBot;
};

bot.use(
    {
        botbuilder: (session, next) => {
            if(!session.userData.version) {
                // new user. set the version
                session.userData.version = bot.version;
            }

            // check if user is in conversation and
            // if the user is on the prior version
            if(session.dialogStack().length > 0 && session.userData.version < bot.version) {
                // load the original bot
                session.library = getOriginalBot(connector);
                // pass control to the original bot
                // the correc step and dialog will be executed
                next();
            } else {
                // update the version in userData
                session.userData.version = bot.version;
                // pass control to the new bot
                next();
            }
        },
    }
);

If you wanted to test this, start by making the new bot version 1 and sending a message to get yourself into the dialog. Then update the version to 2, rerun the application while not restarting the conversation in Bot Emulator, and sending the second message. You should see the original bot message.

Some thoughts on versioning

Versioning is tricky, especially if you’re in a CI/CD environment where you expect to make multiple updates to the bot. Bot Framework (unfortunately?) doesn’t automatically handle transitions for you, so you will need to decide what pattern will work best for you. This is also important when developing and testing your bot in a channel such as Skype or Slack, where how to reset the state from the client isn’t overly obvious. In dev you could certainly skip the transition, but in production you’ll likely want to implement a mechanism for doing so.

Leave a Comment