Add authentication and Qnamaker to bot - bots

I am trying to build a bot using bot framework sdk.
Objective:-
To authenticate user.
afte authentication communicate with Qnamaker knowledge base.
signout user if he types logout
I am using bot authentication template from https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/javascript_nodejs/18.bot-authentication. I have tried to add qnamaker service in the waterflowdialog.
I am facing two issues:-
With every Qnamaker reply I am getting message "you are now logged in".
Bot encountered an error.
Source Code
mainDialog.js
const {
ConfirmPrompt,
DialogSet,
DialogTurnStatus,
OAuthPrompt,
WaterfallDialog,
} = require("botbuilder-dialogs");
const { LogoutDialog } = require("./logoutDialog");
const { QnAMakerDialog } = require("botbuilder-ai");
const CONFIRM_PROMPT = "ConfirmPrompt";
const MAIN_DIALOG = "MainDialog";
const MAIN_WATERFALL_DIALOG = "MainWaterfallDialog";
const OAUTH_PROMPT = "OAuthPrompt";
const QNAMAKER_BASE_DIALOG = "qnamaker-base-dialog";
const createQnAMakerDialog = (
knowledgeBaseId,
endpointKey,
endpointHostName,
defaultAnswer
) => {
let noAnswerActivity;
if (typeof defaultAnswer === "string") {
noAnswerActivity = MessageFactory.text(defaultAnswer);
}
const qnaMakerDialog = new QnAMakerDialog(
knowledgeBaseId,
endpointKey,
endpointHostName,
noAnswerActivity
);
qnaMakerDialog.id = QNAMAKER_BASE_DIALOG;
return qnaMakerDialog;
};
class MainDialog extends LogoutDialog {
constructor(knowledgeBaseId, endpointKey, endpointHostName, defaultAnswer) {
super(MAIN_DIALOG, process.env.connectionName);
this.addDialog(
new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.connectionName,
text: "Please Sign In",
title: "Sign In",
timeout: 300000,
})
);
this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT));
this.addDialog(
new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.promptStep.bind(this),
this.loginStep.bind(this),
this.qnaMaker.bind(this),
])
);
this.addDialog(
createQnAMakerDialog(
knowledgeBaseId,
endpointKey,
endpointHostName,
defaultAnswer
)
);
this.initialDialogId = MAIN_WATERFALL_DIALOG;
}
/**
* The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* #param {*} dialogContext
*/
async run(context, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(context);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
async qnaMaker(stepContext) {
await stepContext.beginDialog(QNAMAKER_BASE_DIALOG);
}
async promptStep(stepContext) {
return await stepContext.beginDialog(OAUTH_PROMPT);
}
async loginStep(stepContext) {
// Get the token from the previous step. Note that we could also have gotten the
// token directly from the prompt itself. There is an example of this in the next method.
const tokenResponse = stepContext.result;
if (tokenResponse) {
await stepContext.context.sendActivity("You are now logged in");
return await stepContext.next();
}
await stepContext.context.sendActivity(
"Login was not successful please try again."
);
return await stepContext.endDialog();
}
}
module.exports.MainDialog = MainDialog;
Bot ScreenShot
github link : https://github.com/chandelsumeet/authBot

async loginStep(stepContext) {
// Get the token from the previous step. Note that we could also have gotten the
// token directly from the prompt itself. There is an example of this in the next method.
const tokenResponse = stepContext.result;
if (tokenResponse) {
await stepContext.context.sendActivity('You are now logged in.');
return await stepContext.prompt(CONFIRM_PROMPT, 'Would you like to view your token?');
}
await stepContext.context.sendActivity('Login was not successful please try again.');
return await stepContext.endDialog();
}
Replace the loginStep() with above code block and check it.

Related

How do I trigger LUIS in all dialogs retaining the previous context?

I am developing a bot with Microsoft Bot Framework, LUIS and node.js .This bot is based on Microsoft Teams and I am using TeamsBotSsoPrompt and Microsoft-Graph for authentication of the user.
The authentication step in the AUTH_DIALOG is as follows:
async showUserInfo(stepContext) {
const tokenResponse = stepContext.result;
if (tokenResponse) {
try {
// Call Microsoft Graph on behalf of user
const oboCredential = new OnBehalfOfUserCredential(tokenResponse.ssoToken);
//console.log("oboCredential> " + JSON.stringify(oboCredential));
const graphClient = createMicrosoftGraphClient(oboCredential, this.requiredScopes);
const me = await graphClient.api("/me").get();
const lanID = await graphClient.api("/me/onPremisesSamAccountName").get();
if (me) {
var authHeaders = {
"user": me.userPrincipalName,
"token": tokenResponse.token,
header1: null,
header2: null,
header3: null,
}
userName = me.givenName;
authHeaders['name'] = userName;
await stepContext.context.sendActivity({ type: ActivityTypes.Typing });
await stepContext.context.sendActivity(`Hello! <b>` + userName + `</b>`);
await stepContext.context.sendActivity({ type: ActivityTypes.Typing });
await stepContext.context.sendActivity("Let's get started.How can I help you?");
return await stepContext.beginDialog(FLOW_DIALOG, authHeaders);
} else {
await stepContext.context.sendActivity({ type: ActivityTypes.Typing });
await stepContext.context.sendActivity("Getting profile from Microsoft Graph failed! ");
return await stepContext.endDialog();
}
}
catch (error) {
// error logged here
}
}
else {
await stepContext.context.sendActivity({ type: ActivityTypes.Typing });
await stepContext.context.sendActivity("Login was not successful please try again.");
return await stepContext.endDialog();
}
}
The FLOW_DIALOG is where I have LUIS enabled.From the FLOW_DIALOG, I redirect the bot to other dialogs based on the Intent.But when I am in that other dialog and if I enter something in the bot, the current dialog ends and returns the flow to the FLOW_DIALOG. I want all the dialogs to trigger LUIS and move the flow to the correct Intent Dialog.
The FLOW_DIALOG is as follows:
async introStep(stepContext) {
const ActionCard = utility.createSuggestedActions(suggestionList, suggestionTitle);
await stepContext.context.sendActivity({ type: ActivityTypes.Typing });
await stepContext.context.sendActivity({ attachments: [ActionCard] });
return { status: DialogTurnStatus.waiting };
}
async actStep(stepContext) {
const luisRecognizer = new LuisRecogniser(luisConfig, stepContext.dialogs.telemetryClient);
let authHeaders = stepContext.options;
if (!luisRecognizer.isConfigured) {
return await stepContext.context.sendActivity("Something went wrong. Please Contact Your Administrator");
}
const luisResult = await luisRecognizer.executeLuisQuery(stepContext.result ? stepContext.result : stepContext.context);
topIntent = LuisRecognizer.topIntent(luisResult);
switch (topIntent) {
case "Intent1": {
authHeaders['header1'] = luisResult.entities;
return await stepContext.beginDialog(DIALOG_A, authHeaders);
}
case "Intent2": {
authHeaders['header2'] = luisResult.entities;
return await stepContext.beginDialog(DIALOG_B, authHeaders);
}
// ... and other intents in similar way
}
}
Now, I did try adding the LUIS to the onMessage call but I couldn't access the context.options to set or reset the authHeaders that I have. I know the context there is DialogContext and the one we get access to is TurnContext.
So is it possible to alter the headers values and pass it along the dialog calls and also trigger LUIS for every message the user enters from whichever Dialog the user currently has access to.
Having LUIS integrated within Waterfall dialogs seems not supported. It worked fine in case of TextPrompt but I find no way to do that when we have 'ChoicePrompt' or 'ConfirmPrompt'.
We can have LUIS integrated to decide which dialog to start and for the same sample is also available - Core bot.
You can also refer this link to have idea on how to use dialogs in bot - https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-concept-waterfall-dialogs?view=azure-bot-service-4.0#using-dialogs

Botframework how to authenticate first and than use the token to make graph api calls

Auth Dialog:
import { ChoicePrompt, DialogSet, DialogTurnStatus, OAuthPrompt, TextPrompt, WaterfallDialog, ComponentDialog } from 'botbuilder-dialogs';
import GraphClient from '../graph-client';
const MAIN_WATERFALL_DIALOG = 'mainWaterfallDialog';
const OAUTH_PROMPT = 'oAuthPrompt';
const CHOICE_PROMPT = 'choicePrompt';
const TEXT_PROMPT = 'textPrompt';
import moment = require('moment');
class AuthDialog extends ComponentDialog {
constructor() {
super('AuthDialog');
this.addDialog(new ChoicePrompt(CHOICE_PROMPT))
.addDialog(new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.ConnectionName,
text: 'Please login',
title: 'Login',
timeout: 300000
}))
.addDialog(new TextPrompt(TEXT_PROMPT))
.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.promptStep.bind(this),
this.processStep.bind(this)
]));
this.initialDialogId = MAIN_WATERFALL_DIALOG;
}
/**
* The run method handles the incoming activity (in the form of a TurnContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* #param {*} turnContext
* #param {*} accessor
*/
public async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
public async promptStep(step) {
return step.beginDialog(OAUTH_PROMPT);
}
public async processStep(step) {
if (step.result) {
// We do not need to store the token in the bot. When we need the token we can
// send another prompt. If the token is valid the user will not need to log back in.
// The token will be available in the Result property of the task.
const tokenResponse = step.result;
// If we have the token use the user is authenticated so we may use it to make API calls.
if (tokenResponse && tokenResponse.token) {
await step.context.sendActivity(`Logged in.`);
} else {
await step.context.sendActivity('something wrong happened.');
}
} else {
await step.context.sendActivity('We couldn\'t log you in. Please try again later.');
}
return await step.endDialog();
}
}
export default AuthDialog;
I have a main dailog which is connected to luis and based on the intent recognized it executes corrosponding code:
for ex i have this in some cases:
case 'CalendarEvents':
return stepContext.beginDialog('AuthDialog');
const calendar = await new GraphClient('token').events();
let eventsBuilder: string = '';
// tslint:disable-next-line: prefer-for-of
for (let index = 0; index < calendar.length; index++) {
const element = calendar[index];
eventsBuilder += '\r\n' + moment(element.start.dateTime).format('dddd, MMMM Do YYYY, h:mm:ss a') + ' - ' + element.subject;
}
await step.context.sendActivity(`${eventsBuilder}`);
So if the intent is CalendarEvents then authenticate and than make some graph api call.
The problem I currently have is that the call to graph api is made before the auth is finished, I would like so first user authenticate and than receives some token and use that token for fetching graph api calls!
any idea how to achieve the above?
Please see the Graph Auth Sample. In particular,
It gets the token in MainDialog:
return step.beginDialog(OAUTH_PROMPT);
[...]
if (step.result) {
const tokenResponse = step.result;
if (tokenResponse && tokenResponse.token) {
const parts = (step.values.command || '').toLowerCase().split(' ');
const command = parts[0];
switch (command) {
case 'me':
await OAuthHelpers.listMe(step.context, tokenResponse);
break;
case 'send':
await OAuthHelpers.sendMail(step.context, tokenResponse, parts[1]);
break;
case 'recent':
await OAuthHelpers.listRecentMail(step.context, tokenResponse);
break;
default:
await step.context.sendActivity(`Your token is ${ tokenResponse.token }`);
}
}
}
[...]
Then, OAuthHelpers uses the token:
static async sendMail(context, tokenResponse, emailAddress) {
[...]
const client = new SimpleGraphClient(tokenResponse.token);
const me = await client.getMe();
await client.sendMail(
emailAddress,
'Message from a bot!',
`Hi there! I had this message sent from a bot. - Your friend, ${ me.displayName }`
);
await context.sendActivity(`I sent a message to ${ emailAddress } from your account.`);
}
This is how the sample works. For you, since you only want to do auth in the Auth dialog, you need to get the token from the user using the Auth dialog, then save it to their UserState, similar to this sample. You can then retrieve their UserState in any dialog and use the token if they have it.
Note
You can either use the Graph API through regular HTTP REST API requests, or use the Graph SDK like the sample does.

Bot Framework v4 Node.js Location

I'm in the process of designing a chat bot and trying to find some Node.js sample code and/or documentation on how to implement the Azure Maps service as part of Bot Framework V4. There are many examples of how this is accomplished in V3, but there seems to be no examples of a V4 solution for Node.js. I'm looking to create a step in my botbuilder-dialog flow that would launch a simple "where do we ship it too" location dialog that would guide the user through the dialog and store the address results as part of that users profile. Any help or advice on this would be appreciated.
Yes, this is doable. I created a class (probably overkill, but oh well) in which I make my API call, with my supplied parameters, to get the map. I decided to use Azure Maps (vs Bing Maps) only because I was curious in how it differed. There isn't any reason you couldn't do this with Bing Maps, as well.
In the bot, I am using a component dialog because of how I have the rest of my bot designed. When the dialog ends, it will fall off the stack and return to the parent dialog.
In my scenario, the bot presents the user with a couple choices. "Send me a map" generates a map and sends it in an activity to the client/user. Anything else sends the user onward ending the dialog.
You will need to decide how you are getting the user's location. I developed this with Web Chat in mind, so I am getting the geolocation from the browser and returning it to the bot to be used when getMap() is called.
const { ActivityTypes, InputHints } = require('botbuilder');
const fetch = require('node-fetch');
class MapHelper {
async getMap(context, latitude, longitude) {
var requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow'
};
const result = await fetch(`https://atlas.microsoft.com/map/static/png?subscription-key=${ process.env.AZURE_MAPS_KEY }&api-version=1.0&layer=basic&zoom=13&center=${ longitude },${ latitude }&language=en-US&pins=default|al.67|la12 3|lc000000||'You!'${ longitude } ${ latitude }&format=png`, requestOptions)
.then(response => response.arrayBuffer())
.then(async result => {
const bufferedData = Buffer.from(result, 'binary');
const base64 = bufferedData.toString('base64');
const reply = { type: ActivityTypes.Message };
const attachment = {
contentType: 'image/png',
contentUrl: `data:image/png;base64,${ base64 }`
};
reply.attachments = [attachment];
await context.sendActivity(reply, null, InputHints.IgnoringInput);
})
.catch(error => {
if (error) throw new Error(error);
});
return result;
};
};
module.exports.MapHelper = MapHelper;
const { ChoicePrompt, ChoiceFactory, ComponentDialog, ListStyle, WaterfallDialog } = require('botbuilder-dialogs');
const { MapHelper } = require('./mapHelper');
const CONFIRM_LOCALE_DIALOG = 'confirmLocaleDialog';
const CHOICE_PROMPT = 'confirmPrompt';
class ConfirmLocaleDialog extends ComponentDialog {
constructor() {
super(CONFIRM_LOCALE_DIALOG);
this.addDialog(new ChoicePrompt(CHOICE_PROMPT))
.addDialog(new WaterfallDialog(CONFIRM_LOCALE_DIALOG, [
this.askLocationStep.bind(this),
this.getMapStep.bind(this)
]));
this.initialDialogId = CONFIRM_LOCALE_DIALOG;
}
async askLocationStep(stepContext) {
const choices = ['Send me a map', "I'll have none of this nonsense!"];
return await stepContext.prompt(CHOICE_PROMPT, {
prompt: 'Good sir, may I pinpoint you on a map?',
choices: ChoiceFactory.toChoices(choices),
style: ListStyle.suggestedAction
});
}
async getMapStep(stepContext) {
const { context, context: { activity } } = stepContext;
const text = activity.text.toLowerCase();
if (text === 'send me a map') {
const { latitude, longitude } = activity.channelData;
const mapHelper = new MapHelper();
await mapHelper.getMap(context, latitude, longitude);
const message = 'Thanks for sharing!';
await stepContext.context.sendActivity(message);
return await stepContext.endDialog();
} else {
await stepContext.context.sendActivity('No map for you!');
return await stepContext.endDialog();
}
}
}
module.exports.ConfirmLocaleDialog = ConfirmLocaleDialog;
module.exports.CONFIRM_LOCALE_DIALOG = CONFIRM_LOCALE_DIALOG;
Hope of help!
---- EDIT ----
Per request, location data can be obtained from the browser using the below method. It is, of course, dependent on the user granting access to location data.
navigator.geolocation.getCurrentPosition( async (position) => {
const { latitude, longitude } = position.coords;
// Do something with the data;
console.log(latitude, longitude)
})

How stepContext.prompt() execute and move automatically to next step in waterfallDialog using BotFramework SDK V4 NodeJS

I'm using Microsoft BotBuilder V4 NodeJs SDK for bot development. I'm facing an issue where I'm recalling my waterfall dialog. Inside, one of the async step() - I'm invoking call for prompt() which is type of textPrompt.
Here, what I'm facing an issue:
On first initial execution cycle of Waterfall Dialog - prompt() works appropriately.
But, on second call for same waterfall dialog - prompt() doesn't wait for user input text. Instead, it move automatically to next async step().
How does it move to the next async step() function in the waterfall dialog without sending another message to bot?
const { ComponentDialog, TextPrompt, WaterfallDialog } =
require('botbuilder-dialogs');
const { CardFactory, ActionTypes } = require('botbuilder');
const initialId = 'Main_Dialog';
const MAIN_WATERFALL_DIALOG = 'mainDWaterfallDialog';
class Main_Dialog extends ComponentDialog {
constructor(conversationState, userState, luisApplication, luisPredictionOptions) {
super('Main_Dialog');
this.luisRecognizer = new LuisRecognizer(luisApplication, luisPredictionOptions, true);
this.conversationData = conversationState.createProperty("mainDialog");
this.userProfile = userState.createProperty("mainDialog");
// Create our bot's dialog set, adding a main dialog and their component dialogs.
this.addDialog(new TextPrompt('PromptTextPrompt', this.waitForUserPromptValidator))
.addDialog(new MyAdaptiveBot('MyAdaptiveBot'))
.addDialog(new Welcome_C_Dialog('Welcome_C_Dialog'))
.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.introStep.bind(this),
this.actStep.bind(this),
this.finalStep.bind(this)
]));
this.initialDialogId = MAIN_WATERFALL_DIALOG;
this.query_flag = false;
this.process_flag = false;
}
async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
async introStep(stepContext) {
if (this.recognizer !== undefined) {
throw new Error('[MainDialog]: LUIS LuisRecognizer not configured properly');
}
return await stepContext.prompt('PromptTextPrompt', 'What can I do for you?', {retryPrompt: 'Sorry, please submit your adverse event case. Otherwise, say cancel.'});
}
async actStep(stepContext) {
const luisResult = await this.luisRecognizer.recognize(stepContext.context);
let switch_case = LuisRecognizer.topIntent(luisResult);
switch (switch_case) {
case "Greetings":
// await turnContext.sendActivity(`Welcome to AECaseBuilder!`);
this.query_flag = true; // set - true query_flag
await stepContext.beginDialog('Welcome_C_Dialog');
break;
case "Enquiry":
//const user_inp = turnContext.activity.text;
await stepContext.beginDialog('MyAdaptiveBot', null);
this.query_flag = false; // reset query_flag
break;
default:
// Catch all for unhandled intents
break;
}
return await stepContext.next();
}
async finalStep(stepContext) {
// Restart the main dialog with a different message the second time around
const messageText = "Whats else can I do for you?";
return await stepContext.replaceDialog(this.initialDialogId, { restartMsg: messageText });
}
async waitForUserPromptValidator(promptContext){
console.log(`prompt : ${promptContext.recognized.value}`);
if(promptContext.recognized.value.trim() === ''){
return false;
}
return true;
}
}
module.exports.Main_Dialog = Main_Dialog;
//#File: Welcome_C_Dialog
const { ComponentDialog, TextPrompt, WaterfallDialog } = require('botbuilder-dialogs');
const { CardFactory, ActionTypes } = require('botbuilder');
const initialId = 'Welcome_C_Dialog';
const welcomeCard = require('./resources/welcome_acb.json');
class Welcome_C_Dialog extends ComponentDialog {
/**
*
* #param {*} id
* #method - constructor()
* #returns - void
*/
constructor(id){
super(id);
// ID of the child dialog that should be started anytime the component is started.
this.initialDialogId = initialId;
// Define the prompts used in this conversation flow.
this.addDialog(new TextPrompt('textPrompt', this.waitForInputValidator));
// Define the conversation flow using a waterfall model.
this.addDialog(new WaterfallDialog(initialId,[
// dialog steps
async function(step){
// Clear the case information and prompt for user to submit new case intake.
step.values.caseInfo = {};
await step.context.sendActivity({
text: "",
attachments: [CardFactory.adaptiveCard(welcomeCard)]
});
// return await step.prompt('textPrompt', 'Waiting for your case intake...',{
// retryPrompt: 'Sorry, please submit your case for AECaseBuilder or say cancel.'
// });
// return MyAdaptiveDialog.EndOfTurn;
return await step.endDialog();
}/*,
async function(step){
await step.context.sendActivity('received case...');
const resultValue = step.result;
//console.log(` input text: ${resultValue}`);
step.values.caseInfo.inputText = resultValue;
return await step.endDialog({inputText: resultValue});
}*/
]));
}
/**
*
* #param {*} promptContext
* #method waitForInputValidator()
* #returns true if case input received successfully. Otherwise, returs false.
*/
async waitForInputValidator(promptContext){
//console.log(`prompt : ${promptContext.recognized.value}`);
if(promptContext.recognized.value.trim() === ''){
return false;
}
return true;
}
}
exports.Welcome_C_Dialog = Welcome_C_Dialog;

How to implement Waterfall Dialog from within a Dialog depending on the LUIS recognized intent in Nodejs?

I have a Main Dialog in which I am having a Waterfall Dialog of only one step which is to Identify Intent and depending on the intent, I am deciding whether to call another dialog (which is another Waterfall Dialog with 3 steps) or directly reply back the user with response for intents like Greeting and Cancel. Below is the code for my Main Dialog -
const chalk = require('chalk')
const path = require('path');
const {
ComponentDialog,
DialogSet,
DialogTurnStatus,
WaterfallDialog
} = require('botbuilder-dialogs');
const {
TopLevelDialog,
TOP_LEVEL_DIALOG
} = require('./topLevelDialog');
const ENV_FILE = path.join(__dirname, '../.env');
require('dotenv').config({
path: ENV_FILE
});
const {
LuisRecognizer
} = require('botbuilder-ai');
const MAIN_DIALOG = 'MAIN_DIALOG';
const WATERFALL_DIALOG = 'WATERFALL_DIALOG';
const USER_PROFILE_PROPERTY = 'USER_PROFILE_PROPERTY';
const dispatchRecognizer = new LuisRecognizer({
applicationId: process.env.LuisAppId,
endpointKey: process.env.LuisAPIKey,
endpoint: `https://${process.env.LuisAPIHostName}`
}, {
includeAllIntents: true,
includeInstanceData: true
}, true);
class MainDialog extends ComponentDialog {
constructor(userState) {
super(MAIN_DIALOG);
this.userState = userState;
this.userProfileAccessor = userState.createProperty(USER_PROFILE_PROPERTY);
this.addDialog(new TopLevelDialog());
this.addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
this.initialStep.bind(this),
]));
this.initialDialogId = WATERFALL_DIALOG;
}
async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
async initialStep(stepContext) {
const recognizerResult = await dispatchRecognizer.recognize(stepContext.context);
const intent = LuisRecognizer.topIntent(recognizerResult);
console.log(chalk.yellow(intent))
await this.dispatchToTopIntentAsync(stepContext, intent);
console.log(chalk.green('after dispatch'))
return await stepContext.endDialog();
}
async dispatchToTopIntentAsync(stepContext, intent) {
console.log(chalk.blue('in dispatch to top intent'))
switch (intent) {
case 'Greeting':
console.log(chalk.red('greeting'))
return await this.greeting(stepContext);
default:
console.log(`Dispatch unrecognized intent: ${ intent }.`);
await stepContext.context.sendActivity(`Dispatch unrecognized intent: ${ intent }.`);
return await stepContext.beginDialog(TOP_LEVEL_DIALOG);
}
}
async greeting(stepContext) {
return await stepContext.context.sendActivity(`Welcome! how can I help you`);
}
}
module.exports.MainDialog = MainDialog;
module.exports.MAIN_DIALOG = MAIN_DIALOG;
In my case, the TOP_LEVEL_DIALOG is being when I type any query related to that intent, and ask the first step of that waterfall (asks for Name).
But when I type my name it comes out of that waterfall dialog and shows the greeting response as LUIS is identifying my name as Greeting intent.
How to solve this kind of issue?
I don't believe the issue is with your code, but with your LUIS model. If you type in your name and it returns the Greeting intent, then you should start by reviewing the utterances in your Greeting intent and how your LUIS model is trained/published.
You should navigate to the LUIS.ai site and test your model by entering your name and see what returns.

Resources