ubreddy
ubreddy

Reputation: 875

botframework v4 proactive messages not going through activityhandler event handlers

I Have a notification dialog to be invoked proactively...

e.g.

Bot: Hi, you have an event scheduled in next 15 mts... blah blah
Bot: would you want me to email the details?
User input: yes/no
Bot: Great!

This is a simple waterfall dialog... step1 inform and prompt confirm. step2. process user input..

Now this dialog is initiated proactively . step 1 works. However the dialogContext / dialogStack is not getting saved and when user says yes it is going to main dailog and not this proactive dialog which should be on top of stack.

Basically, none of the activityHandler methods like onDialog event on the activityHandler are getting invoked for proactive dialog.

Question is how to have the messages from proactive Dialog go through activityHandler methods so that the dialogStack is persisted ?

I use nodejs.

Updating with Code sample below // middleware

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



class MyMiddleware {

    async onTurn(context, next) {


        await context.onSendActivities(async (context, activities, nextSend) => {
            console.log(`messages: ${activities.map( a => a.text).join(',')}`)
            return await nextSend();
        });

        // By calling next() you ensure that the next Middleware is run.
        return await next();
    };


}

module.exports.MyMiddleware = MyMiddleware;

// main bot.

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

class ProactiveBot extends ActivityHandler {
    constructor(conversationReferences) {
        super();

        this.conversationReferences = conversationReferences;

        this.onConversationUpdate(async (context, next) => {
            this.addConversationReference(context.activity);

            await next();
        });

        this.onMembersAdded(async (context, next) => {
            const membersAdded = context.activity.membersAdded;
            for (let cnt = 0; cnt < membersAdded.length; cnt++) {
                if (membersAdded[cnt].id !== context.activity.recipient.id) {
                    const welcomeMessage = 'Welcome to the Proactive Bot sample.  Navigate to http://localhost:3978/api/notify to proactively message everyone who has previously messaged this bot.';
                    await context.sendActivity(welcomeMessage);
                }
            }

            await next();
        });

        this.onMessage(async (context, next) => {
            this.addConversationReference(context.activity);

            await context.sendActivity(`You sent '${ context.activity.text }'`);
            await next();
        });

        this.onDialog(async (context, next) =>{
            console.log(`I am called`)
        })
    }

    addConversationReference(activity) {
        const conversationReference = TurnContext.getConversationReference(activity);
        this.conversationReferences[conversationReference.conversation.id] = conversationReference;
    }
}

module.exports.ProactiveBot = ProactiveBot;

// index

const bot = new ProactiveBot(conversationReferences);

server.post('/api/messages', (req, res) => {
    adapter.processActivity(req, res, async (context) => {
        // Route to main dialog.
        await bot.run(context);
    });

});
server.get('/api/notify', async (req, res) => {
    for (const conversationReference of Object.values(conversationReferences)) {
        await adapter.continueConversation(conversationReference, async turnContext => {
            await turnContext.sendActivity('proactive hello');
        });
    }

    res.setHeader('Content-Type', 'text/html');
    res.writeHead(200);
    res.write('<html><body><h1>Proactive messages have been sent.</h1></body></html>');
    res.end();
});

When I call notify api I expect the onDialog event to be called... and print "I am called". But that doest not get printed to console.

Upvotes: 1

Views: 439

Answers (1)

Steven Kanberg
Steven Kanberg

Reputation: 6418

It looks like you do not have the following bit of code in your "mainBot.js" file. Adding it should solve your problem and not require you to save state after every step. I have a proactive dialog that presents the user with a "yes/no" option, as well. However, I do not have to save with every step in order to capture the user's response.

this.onDialog(async (context, next) => {
  console.log('Dialog detected');

  // Save any state changes.
  await this.conversationState.saveChanges(context, false);
  await this.userState.saveChanges(context, false);

  await next();
});

That being said, I have a component dialog that is listening for the user's choice sending an appropriate response. The proactive dialog is not being captured but the response context is. Because the "mainDailog.js" extends the component dialog the context is added to the stack which is then processed via the this.onDialog() method in "mainBot.js". Thus, state is saved. Check out this SO response I posted recently that demo's this setup which includes the above code but is not displayed. In that case, the user also wanted a timer built into the process which you can ignore.

Hope of help!

Upvotes: 1

Related Questions