Bot-docs: How to use `ConfirmInput` with `AllowInterruptions = true` is not documented well.

Created on 6 Nov 2020  Â·  25Comments  Â·  Source: MicrosoftDocs/bot-docs

This does not explain much about what you should do when AllowInterruptions = true is used.
Specifically in the ConfirmInput case like this:

new ConfirmInput()
{
    Property = "turn.collection.azp",
    Prompt = new ActivityTemplate("Does your service collect profiling data using azure profiler?"),
    InvalidPrompt = new ActivityTemplate("Didn't understand your answer."),
    UnrecognizedPrompt = new ActivityTemplate("Unrecognized input."),
    MaxTurnCount = 3,
    AllowInterruptions = true,
},

If it is interrupted with say help and then the dialog resumes, the Property will never get the value when you answer the prompt properly. In addition although neither the InvalidPrompt nor the UnrecognizedPrompt are printed, all the MaxTurnCounts get used up and the property is unset.

Note that a interrupted ConfirmPrompt uses one of the MaxTurnCount which is not documented either.


Document Details

⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

support customer insufficient information adaptive dialogs

All 25 comments

Hello, @WashingtonKayaker. I see that you added the "team: support" label. Can you please explain what you would like the support team to do for this issue?

@nschuessler - Thank you for the post. Are you asking for help getting adaptive dialog interruptions working, or are you trying to report a bug in the SDK, or are you trying to report a bug in the docs? It looks like adaptive dialog interruptions are pretty well documented here: https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-adaptive-dialog-interruptions

First, missing from the docs is the fact that if you use ConfirmInput and the the input is interrupted, one of the MaxTurnCounts is used up. I.e. if I interrupt the prompt 3 times with a MaxTurnCount of 3, I will not get a chance to actually give the answer !

The link you gave seems to be a page I didn't find before, but it still doesn't quite help.

This bug was about documentation only, because the documentation isn't clear enough (maybe a more explicit example needed) on successfully getting an interupted ConfirmInput to work.

But yes, I also think there is a bug. Because once interrupted, when you come back to ConfirmInput to re-enter, no matter what you enter (valid or not) it will never take the input. It will exhaust MaxTurnCount and give up on the prompt.

I was trying to use ConfirmInput in an AdaptiveDialog in combination with a Q&A LUIS app. With a LUIS adapter routing traffic. When I ask a question it gets routed to Q&A correctly, but when q&A dialog exits, the ConfirmInput doesn't work anymore.

Thank you for the reply, @nschuessler. Would you be willing to help us by coming up with a minimal example that can reproduce the issue? The first thing I have in mind is to determine if LUIS and QnA Maker are relevant, so it would be a good idea to create a new bot with just a Regex recognizer and see if you can reproduce the problem there.

@nschuessler - Are you still working on this?

@v-kydela Yes. I'll try to get to this soon.

Here is a minimal template for testing.
ReproConfirmInput2.zip

Here is the text sequence used to interrupt:
ConfirmInput1
ConfirmInput2

As you can see ConfirmInput works fine with the RegexRecognizer and and no Q&A makers.
However you uncomment this:

* ***** Uncommenting this causes problems
                 new OnIntent(
                    "None",
                    null,
                    new List<Dialog>()
                    {
                        inputDialog,
                    }),
*/

Then it runs the ConfirmInputDialog over and over again which is similar to the type of problem I was seeing.
Side note: why? inputDialog should be the same instance that was filled out eh? Maybe I have to save the result of the dialog into conversation.first and conversation.last

So the problem may be that the dispatch LUIS app that we have is routing things to multiple dialogs (Q&A maker, and our AdaptiveDialog causing similar problems). Our assumption was we had to dispatch inputs to the dialogs until they were finished, but it appears not handling the "None" case doesn't hurt the ConfirmInput dialog from resuming.

Also note: If you take the above example and upgrade from 4.10.3 to 4.11.1 of the framework it doesn't run, it gets a NullReferenceException. I think there is a bug in setting up the UserAgent for HTTP requests or someting.

image
image

Hello @nschuessler. I feel like we're talking about a lot of separate issues that should be in their own posts.

  1. The documentation is unclear
  2. A resumed input does not populate its property
  3. No error message is shown
  4. Max turn count is exceeded prematurely
  5. ConfirmInputDialog runs over and over again
  6. There is a NullReferenceException after upgrading to 4.11.1

I think trying to address them all at once will only cause confusion, so I'd just like to address the first one for now. In order to address this documentation bug, I need to understand more about your expected and actual observed behavior. I am able to run your example successfully, and I'd like to point out that your dialog manager sends the recognizer results and bot state as trace activities to the Emulator every turn. You can read these to get debugging information:

Emulator

It looks like ConfirmInputDialog runs over and over again because you're running it in response to the None intent, and you can see how often the None intent is triggered by reading those recognizer results. You can also read the bot state traces to see which dialogs are on the stack on each turn. It may be a good idea to use a SendActivity action in each intent to let you know what intent has been triggered so you can get a sense of how often the None intent gets triggered even without reading the trace activities.

Looking at your screenshots, it looks like you only provided screenshots of the "good" behavior. Is that correct? If so, what does the "bad" behavior look like and what is your expected behavior?

@v-kydela Even RE: 'None' intent commented out it runs over and over?

The none intent problem happens only when I uncomment the "OnIntent" correct? I.e. you had to uncomment it to get the above results? But the recognizer always is checking the input (even responses to the prompts) and returning 'None' even when the dialogs are running. The recognizer should only take action when there is a change in intent right?

Ok, thanks, I missed the logging information about the bot state, although I don't fully understand it yet.

What is the lifetime of RootDialog and that of the Conversation . The Conversation is the whole interaction between all the dialogs. And once we end the nested dialogs the RootDialog is then terminated and a new one is created on the next input, or is a root dialog created on some other pattern? I don't see dialog identifiers in the bot trace to tell.

I thought that if I do SendActivity then it ends the Turn and would clear all the turn.xxx variables. I had that problem initially so I avoided using SendActivity as a tracing mechanism.

Specifically if I sandwich a SendActivity between the ConfirmInput and the IfCondition the turn variables are cleared (turn.hasfirst), and the IfCondition will always be false. A turn is a request/response pair according to the docs.

                       new ConfirmInput()
                                    {
                                        Property = "turn.hasfirst",
                                        Prompt = new ActivityTemplate("Do you have a first name?"),
                                        InvalidPrompt = new ActivityTemplate("Didn't understand your answer."),
                                        UnrecognizedPrompt = new ActivityTemplate("Unrecognized input."),
                                        MaxTurnCount = 3,
                                        AllowInterruptions = true,
                                    },

                                    new IfCondition()
                                    {
                                        Condition = "turn.hasfirst == true",
                                        Actions = new List<Dialog>()
                                        {
                                            new SetProperty()
                                            {
                                                Property = "dialog.first",
                                                Value = "FirstName",
                                            },
                                        },
                                    },

Q: Is the state protection (saving stuff in dialog.first) the way to handle interruptions of the dialog? It wasn't clear to me that that is what I needed to do from reading the docs, I had to figure it out on my own.

So this was the desired behavior I wanted in my original app:

bot> Do you have xxx configured as a data source?
user> What is xxx?  (redirected to Q&A server)

(asks Q&A a bunch of questions to learn about data sources)

bot> Do you have xxx configured as a data source?
user> yes

bot> What is your team name?
user> What teams are available for SharePoint organization?

<bot gives a list of teams>

<bot> What is your team name?
<user> MyTeam

Instead in my original app with LUIS dispatch and LUIS and Q&A sub apps, the failed behavior was like this:

bot> Do you have xxx configured as a data source?  ** Turn count: 1 **
user> What is xxx?  (redirected to Q&A server)

(asks Q&A a bunch of questions to learn about data sources)

bot> Do you have xxx configured as a data source? ** Turn count 2 ***
user> yes

bot> Do you have xxx configured as a data source? ** Turn count 3 ***
user> yes

** Moves on to next question and doesn't save the result of the previous question because it exceeded turn count but never objected to the input formats or content **

<bot> What is your team name?
<user> MyTeam

Even RE: 'None' intent commented out it runs over and over?

I don't think so.

The none intent problem happens only when I uncomment the "OnIntent" correct?

I think so.

I.e. you had to uncomment it to get the above results?

If by "above results" you mean the input dialog getting triggered every time a None intent was recognized then yes, but it's still unclear what that looks like for you since you only posted screenshots of the good behavior.

The recognizer should only take action when there is a change in intent right?

I think we've identified a source of misunderstanding here. The Bot Framework doesn't have a concept of a "change in intent." We have recognizers and dialogs and interruptions. A common pattern is for a recognizer to be used to recognize intents to determine which dialog to begin, and then subsequent turns will be handled by that chosen dialog until it ends or is interrupted. It is the dialog that persists across turns and not the intent, so the bot doesn't know about or care about what intent started the dialog on some previous turn. Once an intent is processed on one single turn, the intent becomes irrelevant. You may have been thinking an "intent" is actually the same as the actions that an intent triggers, but that's not the case.

What is the lifetime of RootDialog and that of the Conversation [?]

The root dialog is just another dialog that can be ended whenever you want. A conversation is a channel-specific concept that encompasses all activities exchanged using a particular conversation ID, and in many cases it lasts forever.

And once we end the nested dialogs the RootDialog is then terminated and a new one is created on the next input, or is a root dialog created on some other pattern?

This is up to you.

Is the state protection (saving stuff in dialog.first) the way to handle interruptions of the dialog?

I don't think so.

I believe you will get better help if you stick to one question instead of splintering this issue into many questions. Please consider asking each question in its own Stack Overflow post. Can you tell me what one thing will resolve the original documentation bug you posted here?

SDK samples that show how to handle interruptions locally (In dialog) and globally and a pointer (link) to the samples on interruptions? e.g. the coffee example as code.

I think the topic is complex enough that text may not be able to communicate clearly how it works.

Otherwise if you see clarifications by my questions above that are not covered can the docs cover that?

@nschuessler - You can request a new sample here, though it should be noted that there already is a sample here that demonstrates interruptions in adaptive dialogs. There is also a Composer template that demonstrates interruptions.

If you would like to report a bug you can do that here, and make sure you provide a good way to reproduce the bug and explain your expected and actual observed behavior.

The documentation is already pretty extensive, so if you would like a change in the docs can you explain what specific change you would like?

I have given you a small specific example already, which you have ignored. I have also spent 3+ days slimming down repros and and testing scenarios for you.

At this point I don't think you are intending to take any suggestion I provide, or by extension even investigate bugs if I were to file it. You have everything you need to file the NR exception bug.

Hi @nschuessler. Thank you very much for all the work you've done to help us with repros and testing scenarios.

I certainly don't want you to feel like we're ignoring the example you created. Like I said, I was able to run your example successfully. I'm just not sure what bug it's an example of, and I could use some more information about the how to reproduce a specific bug using your example.

You said to uncomment one of the triggers in your dialog, and I did that and was able to see a sort of looping interruption, but that's just because of the way you coded your dialog rather than a bug in the SDK. We are happy to give you support about how to build adaptive dialogs to do what you want them to, and I recommend asking about that on Stack Overflow since my team monitors questions there.

You also said that when you update from Bot Builder 4.10.3 to Bot Builder 4.11.1 you get a null reference exception. The two Bot Builder SDK packages in your project are Microsoft.Bot.Builder.Dialogs.Adaptive and Microsoft.Bot.Builder.Integration.AspNet.Core, so I went through the following steps:

  1. I updated Microsoft.Bot.Builder.Dialogs.Adaptive to 4.11.1 and ran the project and got no exceptions
  2. I updated Microsoft.Bot.Builder.Integration.AspNet.Core to 4.11.1 and ran the project and got no exceptions

I'm not sure what was causing the exceptions in your case but it seems like there must be some difference between your environment and mine. Since the exception seems to be in response to an incoming activity, perhaps it has something to do with our Emulator configurations. Also, sometimes exceptions are thrown that seem like they break things but are actually only visible because of our Visual Studio debugging settings like "just my code." In any case, I'm happy to keep looking into the problem for you but I will need more information from you because I cannot reproduce it on my end.

We certainly have nothing against taking your suggestions, but we need to know what you're suggesting first. And we always investigate every bug that's filed.

@nschuessler I'm an architect on the SDK so let me see if I can help dig into the issues you're seeing lets start with your turn count issue...

Looking at the code it looks like you're correct... We're incrementing the turn count even when an interruption occurs. We probably shouldn't do that so I'll file a bug to resolve that issue. Thanks for pointing this out...

https://github.com/microsoft/botbuilder-dotnet/blob/main/libraries/Microsoft.Bot.Builder.Dialogs.Adaptive/Input/InputDialog.cs#L259

microsoft/botbuilder-dotnet#5040

With regards to this code:

* ***** Uncommenting this causes problems
                 new OnIntent(
                    "None",
                    null,
                    new List<Dialog>()
                    {
                        inputDialog,
                    }),
*/

We don't actually recommend you ever catch the None intent directly because, as you've seen, it will trigger an interruption for every turn by default (you can work around this using a constraint that restricts when it runs.) You should instead use OnUnknownIntent() as that trigger only processes the None intent if there are no currently running actions.

@Stevenic Thanks. I can't find the documentation where 'None' was mentioned but now I'm seeing information on 'OnUnknownIntent' I don't remember seeing before so it should be clear now. Maybe I skipped that call out on the first read through.

In any case this was a fabricated example to try to repro a problem I was seeing in a smaller example, not something I needed. I was trying to figure out if routing extra messages to the ConfirmInput (simulating having a LUIS recognizer) would create the repro.

I opened https://github.com/microsoft/botbuilder-dotnet/issues/5042 as you see above to cover the NR exception with as much detail as I have.

@Kaiqb we should probably do a better job of warning against the direct handling of None in the docs.

Ok. So I think all the documentation/bug issues have been resolved at this point and we can close this one when satisfied.
I will follow up in Jan on why the issue appears in my original code. It seems to be outside the ConfirmInput control at this point.

I'm glad to hear it, @nschuessler. Thanks again.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mdrichardson picture mdrichardson  Â·  6Comments

v-kydela picture v-kydela  Â·  7Comments

wilmol picture wilmol  Â·  3Comments

justinbarias picture justinbarias  Â·  5Comments

4h5j6For picture 4h5j6For  Â·  5Comments