In the previous step, we noticed that there is the possibility for certain intents to be needed several times with different meanings. In this post, we're introducing states to accomplish this.
- Why We Need States
- How States Work
- Adding States with followUpState
- Adding States to the Logic
- Using Unhandled Intent
As mentioned in previous steps, we want our app logic to look like a binary tree, where users play through different scenarios with different things happening depending on which door they choose at the beginning.
However, with the current structure there is no real hierarchy. There's no way to figure out which room in the game the person is currently in.
It looks more like this:
So how can we create some hierarchy?
We need to find some (frictionless) way to save where a user is coming from when going to the next intent. We could do this manually by saving it in a database, or use session attributes. This is basically what we're doing, but without worrying about saving the data ourselves: with Jovo State Handling.
States can be added to any ask method call to make sure the next intent knows from the request where the user is coming from.
In our example, we're adding a BlueDoorState or a RedDoorState to the ask calls to be able to distinguish the Yes- and NoIntents from each other, depending on the door that was previously entered.
In the next step we're going to use states for the first time.
We're doing this by adding a followUpState to the app before an ask call.
Remember the EnterDoorIntent:
For blue, instead of using
We're adding the following.
This way, the state will be saved as a session attribute, and at the next request, we will know where the user is coming from. Let's do the same for the red door, leaving us with this version of the complete intent:
In the next step, we need to add the states to the code.
States can simply be added as objects to the handlers variable.
For example, we're adding the following below the EnterDoorIntent:
And that's it.
If you're testing it in the Alexa Service Simulator, you can see that the states are added as session attributes:
And if you now test the utterance "Yes", you can see that the attribute "BlueDoorState" is set in the request to the left, and that the right YesIntent response is generated:
You can also use the Actions on Google Simulator to test the flow:
Our "happy path" works now, but what if a user answers the first question (the one about the doors) with a "Yes" or "No"? In our current handlers, we don't have a "YesIntent" or "NoIntent" defined outside states.
Let's try that out.
In the Service Simulator, if we answer the first question (so there's no state yet) with a yes, it returns an error:
If we look into our command line, we can find the following error:
Hmm, so what do we do now? We need to make YesIntent and _NoIntent _accessible outside our states as well. There are two options to do this:
- Add YesIntent and NoIntent manually to your global intents like any other intent before
- Use an Unhandled intent to map all missing intents together
For this tutorial, we're going to use the Unhandled intent. This intent acts like a catch-all for any intent that is coming from the request, but can't be found in the handlers variable.
Unhandled can be used for both for global (stateless) intents or state intents.
By adding an Unhandled intent to your global intents (outside any state), you can make sure that no intent falls through.
For the sake of this tutorial, let's just map global unhandled intents to the LAUNCH intent to make sure people know what this game is really about:
And as you can see, this time it worked:
The Unhandled intent can also be used inside a state. For example, if we don't want people to answer the yes-no questions (in the BlueDoorState) with other utterances like "red door," we can add the an Unhandled intent as well:
This makes for a more robust experience whenever you need to guide users through the process. If you want to keep them in the loop until they reach a certain intent, make sure to use followUpState again.
Unhandled intents can also help you find out if people are trying to access different features that aren't part of the flow you imagined. This can help you evaluate the concept of your interaction design. For example, we can log the intent people used:
In the above example, I tried to trick the game by answering to the yes-no question inside the _BlueDoorState _with "open the red door." With the Unhandled intent inside the state, it asks me again to answer with either yes or no.
And this is what was logged into my console:
What happens next? Will the dog wake up and bite the player? What's that sound in the other room?
You now know all the basics you need to dive deeper into the game design and add some additional layers and steps to the plot.
Congrats on finishing this course!