Throughout a conversation, our brains effortlessly track the conversation and collect information. We can use that information to fill gaps and answer questions that we initially planned to ask. One thing that you should keep in mind while building a conversational Alexa skill is how your skill can fill in the gaps to answer a question instead of pestering your customers with additional questions.

But our minds have limits. When I was in college I played way too many video games. One of my favorites was Metroid Prime. I like to collect everything and get 100% completion. I had played through the game so often that I memorized the locations of all the upgrades. My friends would call and tell me where they were in the game and I'd tell them where the upgrades were. I recently visited my childhood home and played Metroid Prime for the first time in over 15 years. The large gap between my last play session took a toll on my memory. I was only able to recall about 80% of the upgrades by memory, and I had to supplement the gaps in my memory with the internet.

On the other hand, Alexa skills are hard-wired to the internet! With a simple web service call, we can combine the information that we received from our customers and answer a follow-up question without asking. This is a powerful tool in your arsenal that allows you narrow down your questioning to the absolute minimum.

Take a moment to watch the video below of how aggravating it could be when a skill asks a customer for information that it technically already has.

As a best practice, your skills should avoid asking questions it knows the answer to.

Conditionally Collecting Slots with The Foodie

The Foodie is a sample skill that utilizes this best practice. It recommends meals and recipes to indecisive hungry people. If the customer chooses to eat out, the skill will prompt them for the city, state, and postal code in order to recommend a restaurant close by that has what they are looking for. The skill uses dialog management to ensure that all the slots have been collected. However, if our customer tells us their postal code, technically we don't need to ask for the city and state since we can use the postal code to look up the missing information ourselves. Likewise, if they give us the city and state, we can use those pieces of information to look up the postal code. Your customers will thank you for doing the heavy lifting yourself.

Dialog management is an amazing tool at your disposal that you can put to use to ensure that your skill collects all the information it needs. At each turn of the conversation, it reports the state (STARTED, IN PROGRESS, COMPLETED) of the conversation and the collected slot values to your skill code. To have the Alexa service automatically prompt for the next unfulfilled required slot, your skill code returns a Dialog.Delegate directive. Your skill can decide it's done collecting slots and simply not return a Dialog.Delegate. Doing so will stop the Alexa service from asking follow-up questions.

A Tale of 3 Handlers

To achieve conditional flexibility, The Foodie uses three handlers:

InProgressCaptureAddressIntentHandler

InProgressHasZipCaptureAddressIntentHandler

InProgressHasCityStateCaptureAddressIntentHandler

Below is a high-level look at how each of the three handlers are built. The bullets appearing under the canHandle are the conditions where the canHandle function returns true. While handle represents the action that takes place.

Take a moment to read through each handler and keep in mind each handler's canHandle conditions and the handle's action.

InProgressCaptureAddressIntentHandler

canHandle

request.type equals IntentRequest

request.intent.name equals CaptureAddressIntent

request.dialogState not equals COMPLETED

handle

return Dialog.Delegate directive

InProgressHasZipCaptureAddressIntentHandler

canHandle

request.type equals IntentRequest

request.intent.name equals CaptureAddressIntent

request.dialogState not equals COMPLETED

request.intent.slots.zip.value exists, not empty

handle

Use zip to lookup data

InProgressHasCityStateCaptureAddressIntentHandler

canHandle

request.type equals IntentRequest

request.intent.name equals CaptureAddressIntent

request.dialogState not equals COMPLETED

request.intent.slots.city.value exists, not empty

request.intent.slots.state.value exists, not empty

handle

Use city and state to look up data.

Upon looking at the three handler's canHandle functions, you'll notice that three of the conditions are the same. They all check the request sent to your skill code to see if it's an IntentRequest, the name of the intent is CaptureAddressIntent, and if the dialogState is not COMPLETED.

The other two handlers also check to see if slot values have been provided. InProgressHasZipCaptureAddressIntentHandler checks for the zip while InProgressHasCityStateCaptureAddressIntentHandler checks to see if both the city and state have been provided. These handlers will use the minimum amount of information they need, lookup restaurants and speak the results without returning the Dialog.Delegate directive ending dialog management thus skipping unnecessary questions!

Remember that dialog management will handle automatically prompting for empty slots as long as our skill returns a Dialog.Delegate directive. If only either the city or state slot has been provided, InProgressCaptureAddressIntentHandler will service the request and the handle function will return the Dialog.Delegate directive. We don’t need to add a fourth handler to check if the dialogState is COMPLETED because we will never let it complete. Our skill is taking a proactive approach and stops interrogating our customer once it has the minimum amount of necessary information.

Handler Order Matters

Last, the order in which you register your handlers is important. The first handler in the list that returns true is the only one that will handle the request. Therefore you'll need register your most restrictive handlers first and put your least restrictive ones near the bottom. Let's take a look at how these three handlers have been registered.

InProgressHasZipCaptureAddressIntentHandler

InProgressHasCityStateCaptureAddressIntentHandler

InProgressCaptureAddressIntentHandler

As you can see, the more restrictive handlers have been defined first while the least restrictive is at the bottom. Let's say for example that we've collected the city slot and the zip slot. The InProgressHasZipCaptureAddressIntentHandler will return true and use the zip to look up restaurants and speak the results. Even though we had the city our first handler returned true first.

On the other hand, what if we only had the state? The first two handlers would return false, but the InProgressCaptureAddressIntentHandler would return true thus Dialog Management would prompt for one of or missing slots. What if our customer gave us all three? In that case the InProgressHasZipCaptureAddressIntentHandler return true because it's the first one in the list even though InProgressHasCityStateCaptureAddressIntentHandler could technically handle the request.

We take the ability of our daily conversational partners to fill in gaps and follow along for granted. When building your skill, take the time to think how you can make your skill more conversational through conditional flexibility. Doing so will make using your skill experience even more delightful because your skill will be able to skip asking unnecessary questions.

Now that you've read through this post, try to think about how you can put these techniques and features to use in your own skills. Let's continue the discussion online! You can find me on Twitter @SleepyDeveloper.