In this step, we will convert the
canHandle intent and state structure of an ASK SDK v2 Alexa Skill project into the Jovo Framework intent and state routing format.
- Introduction to Intent and State Handling in Jovo
- Migrating our First Intent
- Migrating from canHandle to Nested States and Intents
- Next Step
Introduction to Intent and State Handling in Jovo
Compared to the
handle methods of ASK SDK v2, Jovo works with intents and nested states in handler object.
For example, the Hello World handler in a Jovo app looks like this:
Jovo also comes with support to use states, a way to track where in the conversation the user is in.
States can be nested in Jovo and look like this:
Before we dive deeper into state management, let's convert our first intent to the Jovo Framework structure.
Migrating our First Intent
To be honest, technically it's the
LaunchRequest, not an intent that we're taking a look at first. This is the first interaction users have with your voice app, for example when they say "Alexa, open Quiz Game".
For cross-platform compatibility, Jovo maps Alexa
LaunchRequests to a built-in
LAUNCH intent. If you go back to the example above, this looks like this:
In three steps, we're now going to convert the
LaunchRequestHandler of the ASK SDK app to Jovo and then do some testing to see if it worked:
From LaunchRequestHandler to LAUNCH
Let's take a look at the
LaunchRequest part in the app that is using ASK SDK (find the code here):
This adds a
speak command and feeds it with the
welcomeMessage constant (more on that in the next step), and also adds a
helpMessage as reprompt.
Jovo typically uses the
ask method for this, which has a
reprompt parameter. So in this specific case, it could look like this:
Before we can test this out, let's import constants like
helpMessage along with other helper methods from the original project.
Adding Helper Methods and Constants
In the sample code provided by Amazon, there are a bunch of constants that are used to store speech output like
helpMessage, for example (find the code here):
There are also quite a few helper methods (find them here):
For now, let's just copy everything below our handlers. We will tweak some things here and there (and delete some helpers later), but for now this should be enough.
To test the current state of the app, try to run the Jovo Webhook again:
At first, this will throw an error with the message
Cannot read property 'custom' of undefined. This is because of the following (first) line of the constants (find it here):
You can delete this entirely. We don't need it for Jovo projects.
After this, if you
run the Jovo development server again, you should be able to try out
LAUNCH in the Jovo Debugger:
First intent is done! Let's take a look at the other intents.
Migrating from canHandle to Nested States and Intents
As we learned above, ASK SDK v2 projects are typically organized into different handlers that look like this:
In the next steps, we're going through the handlers to set up the intent and state structure as used in Jovo projects. For this, we will mostly focus on the
canHandle part and deal with the logic (
We're starting with this handler structure from the previous step:
Let's take a look at some more intents of the Quiz Game.
Building the Handler Structure
QuizHandler (find code here), ...
DefinitionHandler (find code here) ...
return attributes.state !== states.QUIZ is interesting here. This handler is only triggered when the voice app is not in the
Jovo nested states:
Here, we're referencing the states from an object:
We can add them like this:
However, for this, we would need to move the
states object above the
setHandler method (otherwise it would be undefined when the handler is set, and throw an error). For readability, we will get rid of the
states object and use the Jovo convention to add
State behind every state name:
QuizAnswerHandler (find code here) ...
Only different behavior for
QUIZ state, so it can be added outside, no need to add it to the
RepeatHandler (find code here) and
HelpHandler (find code here) use so called built-in intents provided by Amazon,
You can add these intents to the handler like below. Note that they need to be added in quotation marks because of the
. in the name (otherwise they would be treated as nested object):
For readability and cross-platform capabilities, it can make sense to not use the
AMAZON prefix for the intents in the handler. For this, Jovo offers an
intentMap that can be helpful with a variety of things.
For example, the
intentMap (which you can find in the
config.js file in the
src folder) of a Jovo "Hello World" project already maps
AMAZON.StopIntent to the Jovo
In the below example, we map
AMAZON.RepeatIntent to just
RepeatIntent, and do the same für
In the handler, it would then look like this:
QuizHandler (find code here), ...
Same functionality for both
AMAZON.StartOverIntent. We could solve this with the
intentMap as described in the previous section:
This would solve the problem. However, intent mapping is global, so for every state, the
AMAZON.StartOverIntent would be mapped to
QuizIntent. This could lead to problems if we wanted to use
StartOverIntent in different contexts.
For this you can use Intent Redirects instead of the
intentMap. Redirects like
toIntent route the handler to a different intent, to keep everything organized and readable:
We keep the
AMAZON.StartOverIntent in the
intentMap though, and map it to
END and Error Requests
ExitHandler (find code here) uses three different intents,
If we take a look at the
intentMap again, we can see that
AMAZON.StopIntent is already mapped to
END. We can go ahead and also add the other ones:
END standard intent in Jovo alrady maps
SessionEndedRequests by Alexa and can be used to do some cleanup and also to send a last response (not possible for all types of requests). Let's add it:
There is one more interesting handler in the ASK SDK project: The
ErrorHandler (find code here) is triggered when there is an error in the Alexa Skill:
For this, Jovo offers the
If you followed all the previous steps, your handler should look like this:
As you can see here, the
START state doesn't seem to be used, so we can get rid of that for now. This leaves us with the following intent and state structure:
In the next step, we're going to add some life to the app. Let's do some work on the application logic.