In my previous post on confirming slots with dialog management, I walked through extending our coffee shop sample skill to dynamically confirm a slot with the Dialog.ConfirmSlot directive. If the customer orders coffee, our skill's back end returns the Dialog.ElicitSlot directive to elicit the flavor slot. The flavor costs $0.50 so we use the Dialog.ConfirmSlot directive to seek confirmation of the additional charges.
At the end of the post, I pointed out that there could be a potential problem. What if the user asked for water? That's still a drink, but what if they asked for baseball, unicorns, or lamp? We're going to have to reprompt the customer to provide us with valid value.
We're going to need to do something to validate the data. I also encouraged you to think about how you would solve the problem on your own. I asked, what handlers would you need? How would you re-elicit the slot? What dialog directives would you need?
To solve this problem, I would have created a helper function that given a slot and a set of rules returns true if the slot value is valid. Then I would have created a handler that would determine if a given slot value was invalid and, if so, re-elicit the slot using the Dialog.ElicitSlot directive. However, earlier this week, we announced slot validations for dialog management, which means we actually don't need to write any code as long as our skill is returning the Dialog.Delegate directive. What line of code never breaks, never needs to be tested and never needs to be rewritten? Answer: the line of code you never wrote!
Before we go too deep into slot validation with dialog management, let's recap the coffee shop skill.
Our coffee shop skill allows the customer to order coffee or tea. Based upon their drink of choice, the skill either asks what kind of coffee roast (coffeeRoast) or type of tea (teaType) they want. Furthermore, if they ordered coffee, the skill uses the Dialog.ElicitSlot directive, to ask the customer if they want to add a flavor. They can turn down a flavor by saying, "no thanks." But if they choose a flavor, the skill uses the Dialog.ConfirmSlot directive to seek confirmation of an additional $0.50 for adding the flavor.
Let's take a look at how we would update our coffee shop skill to automatically validate and prompt for our drink slot if the customer choose an invalid option without any additional code.
Now that the slot validation feature has been released, the build tab in the developer portal has been updated so you can add turn on validations. From the OrderIntent, select the drink slot and you'll see two tabs labeled, one labeled Dialogs and the other Validations. Click on the Validations tab and you will be able to create validations rules for your slot.
There are three validation rules you can choose from:
These rules help you dictate how to validate the slot value. For our coffee shop skill, we'll use the third option, "Accept only Slot Type's values and synonyms." This option allows us to define synonyms and have the validator use those in addition to the values to validate what our customer has said.
Upon selecting that option, we'll need to draft some prompts that Alexa will say to re-elicit the slot. To do that, let's think about what Alexa would say if the drink slot was shoes:
I'm sorry but shoes is not something we offer. Which would you like coffee or tea?
Whoops. I'm afraid we don't serve shoes. Which would you like coffee or tea?
Oops! Shoes is not an option. Which would you like, coffee or tea?
Sorry but shoes is not an option. Which would you like, coffee or tea?
While looking through the examples, you may have noticed that each example includes, "Which would you like, coffee or tea?" We include this as the prompt that Alexa will ask the customer when re-eliciting the drink slot. The other thing that these examples have in common is the mention of "shoes." This is a best practice since we are using an implicit confirmation to communicate to the customer that we heard what they asked for, but it's not a valid choice. When we define our samples, how do we repeat our customer's invalid selection without knowing what they'll say ahead of time? Simple: we use the slot. In this case we are validating the drink slot so we'll use that in our sample utterances:
I'm sorry but {drink} is not something we offer. Which would you like, coffee or tea?
Whoops. I'm afraid we don't serve {drink}. Which would you like, coffee or tea?
Oops! {drink} is not an option. Which would you like, coffee or tea?
Sorry but {drink} is not an option. Which would you like, coffee or tea?
Now that we've converted the sample utterances and added them to our model, we'll save and build the model.
While we don't have to write any additional code to do the validation checks, our skill needs to return the Dialog.Delegate directive in order to have the Alexa service automatically validate and re-elicit the slot if the slot is invalid.
We need to return the Dialog.Delegate directive. Our skill's handler functions check for a variety of use cases. Remember our StartedInProgressOrderIntentHandler handler? It's canHandle function returns true if:
request.type equals IntentRequest request.intent.name equals OrderIntent request.dialogState not equals COMPLETED
The handle function returns the Dialog.Delegate directive, which is exactly what we need to have Alexa handle validating the drink slot for us. Therefore, our back end is complete and we don't need to update our code.
Translated to code, our StartedInProgressOrderIntentHandler appears below:
const StartedInProgressOrderIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === "IntentRequest"
&& handlerInput.requestEnvelope.request.intent.name === "OrderIntent"
&& handlerInput.requestEnvelope.request.dialogState !== 'COMPLETED';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.addDelegateDirective()
.getResponse();
}
}
Note: Dialog management validations only support the Dialog.Delegate directive, so if you return a Dialog.ElicitSlot directive, the validations won’t be run on the slot that was elicited. For example, since we use Dialog.ElicitSlot to elicit flavor after we receive a value for coffeeRoast, validations will not be run on Dialog.ElicitSlot.
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.