0

I implemented a bot with the Microsoft BotFramework. For gathering user data, I use ChoicePrompts. When a user doesn't choose one of the proposed options, the ChoicePrompt repeats until the user enters a valid option (this is default behavior from the prompt method).

Unfortunately, after not choosing one of the valid choice options, the user state is refreshed. This means that I lose all the collected user data until that point.

Is this behavior intended or is there a way to prevent this?

FRANZKAFKA
  • 53
  • 2
  • 13
  • UserState should not be cleared when a valid choice is selected. Please share the ChoicePrompt code you are using. – Eric Dahlvang Feb 22 '19 at 17:29
  • As @EricDahlvang mentioned, if you could post your code, that would help immensely. Can you also verify that user state is, in fact, getting saved before it is refreshed? – Steven Kanberg Feb 22 '19 at 19:45
  • Hello, thanks for your reply. @EricDahlvang the UserState is only cleared when a non-valid choice is selected. You can find my code here: https://stackoverflow.com/questions/54635967/choiceprompt-clears-userstate-or-stepcontext – FRANZKAFKA Feb 23 '19 at 18:07

1 Answers1

1

You have a couple issues with your code on the link you provided. As I can't see your complete code, I've made a guess at some parts.

  1. Double check userState and userData are properly setup. My constructor looks like this:
const DIALOG_STATE_PROPERTY = 'dialogState';
const USER_PROFILE_PROPERTY = 'user';

const EDUCATION_PROMPT = 'education_prompt';
const MAJOR_PROMPT = 'major_prompt';

constructor(conversationState, userState) {
    this.conversationState = conversationState;
    this.userState = userState;

    this.dialogState = this.conversationState.createProperty(DIALOG_STATE_PROPERTY);
    this.userData = this.userState.createProperty(USER_PROFILE_PROPERTY);

    this.dialogs = new DialogSet(this.dialogState);

    // Add prompts that will be used by the main dialogs.
    this.dialogs
        .add(new TextPrompt(NAME_PROMPT))
        .add(new TextPrompt(AGE_PROMPT))
        .add(new TextPrompt(GENDER_PROMPT))
        .add(new ChoicePrompt(EDUCATION_PROMPT))
        .add(new ChoicePrompt(MAJOR_PROMPT));

    // Create dialog for prompting user for profile data
    this.dialogs.add(new WaterfallDialog(START_DIALOG, [
        this.promptForName.bind(this),
        this.promptForAge.bind(this),
        this.promptForGender.bind(this),
        this.promptForEducation.bind(this),
        this.promptForMajor.bind(this),
        this.returnUser.bind(this)
    ]));

    this.majors = ['English', 'History', 'Computer Science'];
}
  1. Remember that TextPrompt returns the value in step.result. ChoicePrompt returns the value as step.result.value

    I'm assuming that in your "promptForEducation" step where you assign the gender value to user that that value is coming from a choice prompt. If not, you will lose the value. Double check you are specifying the correct source.

.add(new TextPrompt(GENDER_PROMPT))
.add(new ChoicePrompt(EDUCATION_PROMPT))

...

if (!user.gender) {
    user.gender = step.result;
    // Give user object back to UserState storage
    await this.userData.set(step.context, user);
    console.log(user);
}
  1. In the "promptForMajor" step, the 2nd parameter in step.Prompt takes a string and represents the dialog portion of the choice. Your code should look like this and will produce the following output. In this instance, I assigned values to "this.majors" in the constructor (shown above).
this.majors = ['English', 'History', 'Computer Science'];

...

if (!user.major) {
    // Copy List of majors and add "Other" entry
    let majorsOther = this.majors.slice(0, this.majors.length);
    majorsOther.push('Einen anderen Studiengang');
    // return await step.prompt(MAJOR_PROMPT, this.userData.major, majorsOther);
    return await step.prompt(MAJOR_PROMPT, 'List of majors:', majorsOther);
}

enter image description here

  1. Check that you are saving state at the end of the "onTurn".
// Save changes to the user state.
await this.userState.saveChanges(turnContext);

// End this turn by saving changes to the conversation state.
await this.conversationState.saveChanges(turnContext);

If you implement the above, you should be set. I was able to run with no issues and no loss of state. Additionally, repeatedly not answering the ChoicePrompt before finally providing a proper response did not break state.

enter image description here

Hope of help!

Community
  • 1
  • 1
Steven Kanberg
  • 6,078
  • 2
  • 16
  • 35