Skip to content

Instantly share code, notes, and snippets.

@jbelmont
Forked from habuma/YesNoIntents.adoc
Created March 12, 2021 00:27
Show Gist options
  • Save jbelmont/b3a3197a1683085e88f8201d75fafadf to your computer and use it in GitHub Desktop.
Save jbelmont/b3a3197a1683085e88f8201d75fafadf to your computer and use it in GitHub Desktop.
Handling Yes/No Intents in an Alexa Skill

An Alexa skill may ask a user a Yes/No question and the response handled by request handlers for the built-in AMAZON.YesIntent and AMAZON.NoIntent intents. (This is different than dialog confirmation where Yes/No confirmation is handled by the dialog.)

It’s easy to setup these intents and their respective intent handlers. Just like any intent, declare them in the interaction model:

{
  "name": "AMAZON.YesIntent",
  "samples": []
},
{
  "name": "AMAZON.NoIntent",
  "samples": []
},

And then create request handlers in the fulfillment code:

const YesIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.YesIntent';
    },
    handle(handlerInput) {
        .... // handle yes intent
    }
}

const NoIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.NoIntent';
    },
    handle(handlerInput) {
        .... // handle no intent
    }
}

Easy peasy, right?

Except for one thing: How do these intent handlers know what the user is saying yes or no to? What if the skill asks more than one yes/no question? How can the intent handler correlate the yes or no answer to a specific question? Also, what’s to stop a user from uttering "Yes" or "No" randomly and triggering these intent handlers, without being asked a question?

We need to set some context by stowing the asked question in a session attribute. To do that, define the following function:

function setQuestion(handlerInput, questionAsked) {
  const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
  sessionAttributes.questionAsked = questionAsked;
  handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
}

Then, in the request handler that poses the question, call setQuestion() to set the context:

handle(handlerInput) {
    const speakOutput = handlerInput.t('ASK_QUESTION');
    setQuestion(handlerInput, 'IsItSunnyOutToday');
    return handlerInput.responseBuilder
        .speak(speakOutput)
        .reprompt(speakOutput)
        .getResponse();
}

Now, change the canHandle() function of the yes/no intent handlers to check for that session attribute (shown here for AMAZON.YesIntent, but the same change applies for the AMAZON.NoIntent request handler):

canHandle(handlerInput) {
    return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
        && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.YesIntent'
        && handlerInput.attributesManager.getSessionAttributes().questionAsked === 'IsItSunnyOutToday';
},

Now when the user says "Yes" or "No", the request handler will only be invoked if the question asked can be determined from the questionAsked session attribute. If the attribute is null or doesn’t match the value expected, then it will remain unhandled. (You could also define a pair of catch-all handlers to tell the user that you don’t know what they were saying yes or no to in that case.)

When handling the yes and no intents, be sure to clear out the session attribute:

setQuestion(handlerInput, null);

This is especially important if the skill may go on to ask more questions to avoid a mishandling of the yes/no intents.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment