Build Advanced Alexa Skills: Confirm What Customers Want with Dialog Management

Justin Jeffress May 10, 2018
Share:
Dialog Management Tutorial Tips & Tools
Blog_Header_Post_Img

When your skill performs a task for the customer that requires information from them, it's a best practice to confirm you have the information you need before performing the task. For example, if you have a skill that can book a flight that will result in a charge for the ticket, your skill should ask for confirmation before making the charge.

With dialog management, you have two options at your disposal to confirm what the customer provided. You can confirm individual slots with confirmSlot or the intent with confirmIntent. You can either set the confirmations from the developer portal while designing your customer interaction model, or programmatically from your AWS Lambda function.

When to Use Slot Confirmations

While it is entirely possible to confirm each slot you've collected from the customer during the conversation, it can add more steps to the interaction. Let's consider a conversation where we confirm each slot during the conversation.

        Alexa: Where are you flying?   
        Customer: Tokyo
        Alexa: Are you flying Tokyo?
        Customer: Yes
        Alexa: Where are you leaving?
        Customer: Next Friday
        Alexa: Are you leaving Next Friday?
        Customer: Yes
        Alexa: When are you coming back?
        Customer: May 30th
        Alexa: Are you coming back May 30th?
        Customer: Yes

While we are only collecting three slots, destination, startDate, and endDate, the number of questions we ask the customer has doubled! Half of the questions are confirming data that the customer has already provided. In a real-life scenario, booking a flight will require more than three slots. We will most likely need things like seat preferences, frequent flyer numbers, preferred airlines, preferred departure times, meal selections, dietary restrictions, and more. Because confirming every slot doubles the amount of questions for the customer, use slot confirmations sparingly.

You should confirm things when a mistake could be inconvenient for the customer like performing an action that affects others (sending a text message) or buying something (like booking a flight). For our booking a flight example, it would be best to restrict slot confirmation to confirm things that can be prone to error or could be important to the customer such as the frequent flyer number and dietary restrictions.

Last, we can use an intent confirmation to ensure that we've properly collected the information the customer provided and they intend to make the reservation.

Confirming the Intent

The Dialog management feature of Alexa Skills Kit facilitates slot collection by creating a state machine that keeps track of the required slots – both collected and uncollected. At each turn of the interaction, our backend can tap into this state machine, check the dialogState (STARTED, IN_PROGRESS, COMPLETED), and delegate the collection of the remaining slots back to Alexa or override the default behavior by returning another dialog directive, such as elicitSlot (prompt for slot value), confirmSlot (prompt for slot confirmation), or confirmIntent (prompt for confirming the intent).

Using an intent confirmation, the customer has the opportunity to say "yes" or "no." The confirmationStatus is included in the JSON sent to and from your skill. Before the intent has been either confirmed or denied, the value is NONE. If the customer confirms the intent, confirmationStatus will be CONFIRMED and if the customer says, "no" confirmationStatus will be DENIED.

It’s important to note that it's up to you to handle the situation when the confirmationStatus is DENIED. If you simply check that the dialogStatus is COMPLETED and book the flight, there is a chance that you might book the flight even though the customer said, "no." To prevent our skill from getting into this state, we will check if confirmationStatus is DENIED while our dialog is still IN_PROGRESS.

Let's take a look at this code written using the Alexa Node.js SDK v2 to handle our intent request:

Copied to clipboard
const StartedInProgressBookFlightIntent_Handler =  {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
       
        return request.type === 'IntentRequest'
            && request.intent.name === 'BookFlightIntent'
            && request.dialogState !== 'COMPLETED';
    },
    handle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        const responseBuilder = handlerInput.responseBuilder;
       
        console.log(request.dialogState);
        console.log(request);
       
        if (request.intent.confirmationStatus === "DENIED") {

            const attributesManager = handlerInput.attributesManager;

            let sessionAttributes = attributesManager.getSessionAttributes();

            sessionAttributes.canceledSlots = currentIntent.slots;

            attributesManager.setSessionAttributes(sessionAttributes);


            return handlerInput.responseBuilder
                .speak("You've canceled your reservation. You can say book a trip to start over.")
                .reprompt("Say book a trip to start over.")
                .getResponse();
        }
       
        // delegate to Alexa to collect all the required slots
        const currentIntent = request.intent;
        if (request.dialogState && request.dialogState !== 'COMPLETED') {
            return handlerInput.responseBuilder
                .addDelegateDirective(currentIntent)
                .getResponse();
        }
    }
};

Our StartedInProgressBookFlightIntent_Handler's canHandle function indicates that it can handle requests for the BookFlightIntent when the dialogState isn't COMPLETED (in other words, when the state is STARTED or IN_PROGRESS). In the handle function, we are checking the request.intent.confirmationStatus and if it's DENIED we cancel the reservation and tell the customer that they can start over. In case the customer wants to change a few slot values, we could save our destinationstartDate,  and endDate slots into the session attributes. If the customer asks to book a flight again, we can detect that the previous match was canceled and we can ask the customer if they want to start over or confirm each slot so the customer can correct.

Saving the Slots

The following code saves our previously collected slots into the session attributes.

Copied to clipboard
const attributesManager = handlerInput.attributesManager;

let sessionAttributes = attributesManager.getSessionAttributes();

sessionAttributes.canceledSlots = currentIntent.slots;

attributesManager.setSessionAttributes(sessionAttributes);

Detecting a Cancelation

We can make another event handler that will handle requests for the BookFlightIntent when the previous action was canceled.

Copied to clipboard
const StartedInProgressPreviouslyCanceledBookFlightIntent_Handler = {

    canHandle(handlerInput) {

    const attributesManager = handlerInput.attributesManager

    const sessionAttributes = attributesManager.getSessionAttributes();


    return handlerInput.requestEnvelope.request.type === "IntentRequest"

      && handlerInput.requestEnvelope.request.intent.name === "BookFlightIntent"

      && handlerInput.requestEnvelope.request.dialogState !== "COMPLETED"

      && sessionAttributes.cancelledSlots;

  },

  handle(handlerInput) {

    const attributesManager = handlerInput.attributesManager

    let sessionAttributes = attributesManager.getSessionAttributes();


    const destination = sessionAttributes.canceledSlots.destination.value;


    return handlerInput.responseBuilder

      .speak(`Last time you were planning a trip to ${destination} would like to continue or start over?`)

      .getResponse();

  }

}

Our canHandle function will return true for requests to the BookFlightIntent while the dialogState is not COMPLETED (which will be either STARTED, or IN_PROGRESS) and we have canceledSlots which we saved to the session attributes. Once we service the request, we will need to remove the session attributes, which we can do with the following code:

Copied to clipboard
const attributesManager = handlerInput.attributesManager

let sessionAttributes = attributesManager.getSessionAttributes();

sessionAttributes.canceledSlots = null;

attributesManager.setSessionAttributes(sessionAttributes);

In the above code, we simply load the session attributes and set canceledSlots to null. Saving the session attributes with setSessionAttributes will result in deleting them.

When designing your skill interactions, consider the outcome and if a confirmation would create a positive experience. Remember to check if the customer confirmed or denied the intent and handle it appropriately.

If you have any questions, let's continue the discussion. You can follow me on Twitter @sleepydeveloper. I may end up writing a blog post to answer your question!

More Resources on Dialog Management

Make Money by Creating Engaging Skills Customers Love

When you create delightful skills with compelling content, customers win. You can make money through Alexa skills using in-skill purchasing or Amazon Pay for Alexa Skills. You can also make money for eligible skills that drive some of the highest customer engagement with Alexa Developer Rewards. Learn more about how you can make money with Alexa skills, and download our guide to learn which product best meets your needs.