Skip to content
This repository has been archived by the owner on Apr 22, 2024. It is now read-only.

Commit

Permalink
Suggestion for on-responded on prompts
Browse files Browse the repository at this point in the history
On issue microsoft#3947, relying on the responded flag todecide whether to show the prompt interferes with logic that could be happening either

a. Concurrently
b. On some middleware
c. As part of how we reached the prompt

I believe the *intention* is to prevent sending a prompt twice to the user, using a symbol may be enough for that, without relying on global status
  • Loading branch information
alexrecuenco committed Nov 30, 2021
1 parent 2bd9b49 commit afec649
Showing 1 changed file with 51 additions and 2 deletions.
53 changes: 51 additions & 2 deletions libraries/botbuilder-dialogs/src/prompts/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,29 @@ export abstract class Prompt<T> extends Dialog {
*/
protected constructor(dialogId: string, private validator?: PromptValidator<T>) {
super(dialogId);

if (validator){
this.validator = async (prompt) => {

const hasRespondedBeforeValidator = prompt.context.responded;
// Making the validator *only* consider as "responded" if responded has been set during a turn
// @ts-expect-error
prompt.context._respondedRef.responded = false;
try {
const result = await validator(prompt);
if (prompt.context.responded) {
if (prompt.context.turnState.get(Prompt.shouldReprompt) == null){
Prompt.setRepromptStatus(prompt.context, false);
}
}
return result;
} finally {
if (hasRespondedBeforeValidator) prompt.context.responded = true;
}
}
}


}

/**
Expand Down Expand Up @@ -206,6 +229,31 @@ export abstract class Prompt<T> extends Dialog {
return Dialog.EndOfTurn;
}

/**
* By default the bot re-prompts if there has not been any message sent to this user in this turn
*
* However, that might be undesirable, you can set here whether you want it to reprompt or not.
*
* To reset to the default status, you can set it back to undefined or null.
* @param context
* @param shouldReprompt
*/
static setRepromptStatus(context:TurnContext, shouldReprompt: boolean | undefined | null = true) {
context.turnState.set(this.shouldReprompt, shouldReprompt);
}

protected shouldReprompt(context: TurnContext): boolean {
const shouldReprompt = context.turnState.get(Prompt.shouldReprompt);
if (shouldReprompt == null) return !context.responded;
return shouldReprompt;
}


/**
* Optional symbol to be used to *force* the context whether to reprompt or not based on the flag
*/
private static shouldReprompt = Symbol('shouldReprompt');

/**
* Called when a prompt dialog is the active dialog and the user replied with a new activity.
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
Expand Down Expand Up @@ -238,6 +286,7 @@ export abstract class Prompt<T> extends Dialog {

// Validate the return value
let isValid = false;

if (this.validator) {
if (state.state['attemptCount'] === undefined) {
state.state['attemptCount'] = 0;
Expand All @@ -257,9 +306,9 @@ export abstract class Prompt<T> extends Dialog {
if (isValid) {
return await dc.endDialog(recognized.value);
} else {
if (!dc.context.responded) {
if (this.shouldReprompt(dc.context)) {
await this.onPrompt(dc.context, state.state, state.options, true);
}
}

return Dialog.EndOfTurn;
}
Expand Down

0 comments on commit afec649

Please sign in to comment.