article by Frank Nimphius, September 2020
The principle of how Oracle Digital Assistant works is that all user messages and interactions with skills are routed by the digital assistant. A digital assistant is a concierge bot that uses machine learning model to find the best matching skill and intent therein to route a request to. In addition to routing messages between a user and a skill, a digital assistant maintains a conversational context that enables users to e.g. pause a current conversation for a new conversation, from which they return to the interrupted conversation or not.
Some functions in a digital assistant are typically required by many skills. An example of such functionality is user authentication, which should be performed once for a digital assistant, but must be triggered by all skills of a digital assistant. You could duplicate the code it takes to perform user authentication into each skill or look for a way to modularize the problem. A feature to modularize the problem is to have a skill calling a skill, which is a feature built-in to Oracle Digital Assistant.
image src: pixabay.com
This article discusses the options and techniques skill developers have available and the practices to follow to implement shared functionality in a separate skill. It is important to mention that the intention of this article is not to say "you must use skill-to-skill conversation" all the time because often a custom component can also be used to wrap and share common functionality. Even copying shared code into several skills sometimes doesn't pose a burden or overhead. This article introduces skill-to-skill calls as a way to share functionality through modularization. Its one more tool in your tool box.
Skill-Calling-Skill Overview
At the time of writing, Oracle Digital Assistant supports two approaches for a skill to invoke another skill. As you will see, the approaches are technically similar but differ in the functionality.
Calling a Skill in a sub-flow
The first scenario is where the conversation returns to the calling skill after the called skill has finished its work. For this, you need to preserve the calling skill's state and context, which includes the position in the conversation. A practical example of this flow would be a user who wants to check the balance on a gift card before making a purchase in a retail bot. In this example, the user definitive wants to return to the conversation where she had left it to continue or cancel the purchase. To implement this use case in Oracle Digital Assistant, the called flow is opened in a sub-flow that has its own dialog flow context. To share information between the calling skill and the called skill, you would use variables you define in a user scope (e.g. user.username).
Abandon the current skill
In the second scenario, the calling skill exits after calling another skill. This behavior is for all use cases in which you don't want to return to the calling skill when the called skill finished its work.
A practical usecase for this is to implement a custom global help functionality. Oracle Digital Assistant allows you to replace the default global help functionality with a custom skill. Your custom skills could, for example, only show the skills you want a user to work with. Using buttons that perform navigation to another skill, a user could choose the functionality (skill) to navigate to, after which the global help skill is extited.
A second usecase for when to exit the calling skill is a shared authentication flow. This example is also covered in the example that you can download for this article.
Skill-Calling-Skill In Action: The Sample
The screenshots in this section are taken from a sample you can download for this article. The zip file you can download needs to be imported as a digital assistant in Oracle Digital Assistant 20.08 or later. After importing the sample, you can try it using the embedded conversation tester. In the context of a pasta order flow, you will be able to explore the following skill calling functionality
- After you chose one or many pastas for an order, you complete the order for an order summary to display. The order summary allows you to actually order the selected pastas, cancel the order or check your account balance at digital bank. Once you completed the account balance check, the conversation resumes exactly where you had left it to complete or cancel the order.
- When continuing the order, the pasta flow requires you to be authenticated. As you are initially not authenticated, you get the option to navigate to an authentication skill. In the authentication skill, you provide a username (choose whatever you want) and password (you need to solve a mathematical quiz) to then resume to the order. This use case uses a call that exists the caller flow for navigating to the authentication flow (skill) and back to the calling skill. You don't want the authentication flow to be in a sub-flow because a sub-flow continues where the calling skill was left, which would be by displaying that you are not authenticated (which however would no longer be true).
The second use case requires you to return to the dialog flow state right after the authentication prompts to continue the pasta order check-out. For this you learn how to take a snapshot of the skill state and how to resolve it when the navigation goes from the authentication skill to the pasta order skill.
Calling a skill in a sub-flow
The first use case in this example starts when the pasta bot displays the summary for an order. As you can see in the image below, there are three buttons displayed. The third button actually performs the navigation to another skill using a sub-flow.
When a user presses the Check Account Balance button, then digital assistant shows an interruption dialog to indicate to the user that he leaves the current skill to continue in another skill. If this navigation is not what the user intended to do, then she could cancel the navigation and immediately return to the calling skill.
Lets assume the user is happy with the navigation and pressed Yes. The called Digital Bank skill now displays a list fo accounts for the user to select from. If the user selects an account, the balance on this account is displayed and the digital assistant is ready to resume back to the calling skill. The users would press Yes to then get back to where the conversation was left in the pasta order conversation.
The image below shows the calling skill conversation state after the user returned. All dialog flow variables have exactly the same value they had before.
Note The pasta summary is only re-rendered. It is NOT re-executed, which means that it cannot be skipped. This is why you need to make sure you pick the right skill-calling-skill solution for the usecase to implement. In this example, the behavior is exactly as i wanted it.
Refining the user experience
In the example you could see interruption dialogs getting displayed by Oracle Digital Assistant before navigation transitions to a next skill. While those dialogs are useful, you may want to suppress them to give users the experience that its one giant bot they are talking to and not one composed out of many smaller chatbots.
To suppress the interrupt dialogs, you got to the digital assistant settings panel as shown in the image below.
Change the Interrupt Prompts Confidence Threshold to a low value. In the image below, the threshold is set to 0.3. What this means is that if the bot has a confidence of at least 30% that it should navigate to another skill, the prompt is not displayed. If you also don't want a message to be displayed when leaving one skill for another, then you empty the Interrupt Message field as shown in the image below.
Similar you set the Resume Response Type field to message (instead of prompt) and clear the Resume message field. This way no system message is displayed when the user returns to the calling skill
The image below show the example shown in the previous section with the applied configurations. As you can see, the conversation navigates straight from the pasta order use case to digital bank to display the user account statement.
When the user then selects an account to see the balance, navigation goes directly to the calling skill.
Still you can see the navigation flow from the calling skill to the called skill in the embedded conversation tester (image below). Notice how the single blue line to the dialog flow steps with the green circle indicate that the skill call is made in a sub flow and that the returning call goes back to the very same dialog flow state in the calling skill.
Abandon the current skill
In the use case described in this section, the calling skill is terminated when the navigation switches to the called skill. There are two sub-usecases to this
- The called skill completes its user conversation to then navigate back to the calling skill
- The called skill does not return to the calling skill and instead may itself call a skill after which it gets terminated
Sub-usecase 1: One scenario for this is an authentication skill. The authentication skill is invoked when another skill requires an authenticated user. Since the conversation in the calling skill should resume on a different state than where it was left for authentication, you implement it so that the calling skill is terminated. If you need to direct back to the calling skill after authentication, you again use a skill-calling-skill call. The skill you call would start at its beginning and will have reset all its dialog flow states. So when you resume to a calling skill you need to make sure that you recover the previous dialog flow context. The sample I share with this article uses a custom component for this.
Sub-usecase 2: A user who works in a specific skill may request help. As the user is in a skill, the local help defined and configured for that state will be displayed. As a developer you want to provide an option to navigate to the global help in case the user doesn't find what she is looking for. So here, assuming you use a custom help skill in digital assistant, you navigate out of the current skill and into the global help skill. If then the user selects an option in the global help skill, this navigation can go everywhere without a sub-flow being kept open.
Example: Authentication Flow
The sample digital assistant that you can download for this article has an authentication scenario implemented. As shown in the image below, when the user confirms the order summary to complete the order, the user is required to authenticate if not already.
Pressing the log me in button performs navigation to the authentication skill. The authentication skill in the example asks for a user name and for a password (which is to solve a math challenge).
If a user passes the challenge she is considered authenticated (at least for this example). She then can resume to the order process or cancel the order (an option not displayed in the image below)
So pressing the button to resume the pasta order conversation does the following things
- abandon the authentication skill
- call the pasta order skill
- restore the pasta order dialog flow context
- navigate to the next state after the state asking the user to authenticate
The embedded conversation tester shows the sequence of navigation as shown in the image below
Notice tat this time there are two dotted lines indicating the state and navigation that left the calling skill and the navigation and state it gets resumed to (in a new invocation).
How-To: Skill-Calling-Skill
As mentioned before, all skill calls to another skill must include digital assistant to keep it managing the conversation state. For this, each navigation is triggered by a message a skill sent to digital assistant. The technique used for a skill calling another skill is identical for all the use cases explained in this article. The message itself is different:
- A skill that opens a called skill in a sub-flow uses explicit navigation. Explicit navigation uses the name of the target skill within the message. The name of the target skill is the "invocation name" displayed in digital assistant.
- A skill that gets abandoned after calling another skill uses an implicit invocation. The implicit invocation sends a message that resolves to the skill you want to call. Implicit navigation is a bit more tricky than explicit navigation as you need to find an utterances to send as a message that perfectly matches to the target skill you want to navigate to.
Calling a skill in a sub-flow
So lets look at the use case in which the new skill opens in a sub-flow first. In the example, the scenario is when the order pasta skill called digital bank. The image below shows the two skills involved in this
The code that you, as the skill developer, need to add is in the calling skill, which is Pasta Alfredo.
The ShoOrderSummary state in line 325 in the BotML editor summarizes the order items for a pasta order. At the end you have action items defined of which one is to check the account balance
Lines 377 and 370 actually do the trick of calling out to another skill. The system.textReceived action and the system.text variable must be used in a System.CommonResponse component for this to work. There is no other option yet available.
Notice line 379 saying "ask <reference to skill parameter>, whats my balance". For the sample, "whats my balance" is the utterance to send to digital assistant. When the reference to the skill parameter gets resolved at runtime, the call is "ask digital bank, whats my balance"
The skill parameter shown in the image above has its default value set to "digital bank". This value can be changed on the digital assistant level in case that a digital assistant developer decides to rename "digital bank to e.g. "neural bank" or similar.
All that the check account balance state in the finance bot needs to do to return to the calling skill is to issue a return transition after printing the balance.
Abandon the current skill
This use case is a bit more complex. So its best to discuss this step-by-step
Calling the authentication service skill
In the Pasta Alfredo With Login skill, you find the following code in line 400 and following:
Line 400 checks a user scope variable whether it holds a value or not. If it does not have a value, then it is assumed that the user wasn't authenticated before. In this case, the System.Switch component continues the conversation in line 413. Because the calling flow will be terminated, it is required to take a snapshot of the required variables. In this example only the variable that holds the user orders is remembered. The custom component could also take a snapshot of multiple variables. If e.g. you want to take a snapshot of iResult and customerOrder, then you would use the following configuration:
snapshot:
– customerOrder
– iResult
This then saves the content of both variables in a user scope variable that is abstracted by the custom component.
With the snapshot taken, the transition goes to line 424. This uses the same action definition as in the previous use case. If you look at line 438 and 440 you see system.textReceived being used as the action and system.text being used as the variable. The difference to the example before is that the message that gets sent to digital assistant does not contain the name of the skill to call. "Authenticate me" does resolve to the authentication skill
The logon skill now processes the user authentication to then pass the navigation back to the calling skill (which the resumes from a fresh start)
In line 111 and following, the authenticated user name is saved in the suer scope variable used by all skills to check for an authenticated user. In a production chatbot I would probably create custom components for getting and setting the user name to a user scope variable to shield developers from knowing what the name of the variable is (this technique is subject of another article for me to write).
Line 132 and 134 then loop back to the order pasta skill when the user presses the resume button.
Note that in a production chatbot the returning utterances "I like to order pasta" should not be hard coded as you will have multiple skills requiring authentication. So its better to pass the returning utterances with the request to the authentication skill. So in the interest of lowering complexity for this sample I simple provided the return utterance as a static string. Don't do the same in production but use another user scope variable.
Resuming the pasta order skill
So the authentication skill returns to the pasta order skill, which now starts at the beginning (first dialog flow state) and need to restore its previous state from the snapshot
First, the dialog flow uses two more custom components: one component to restore the snapshot and another to clear the snapshot.
It doesn't matter how many variable states you saved in the snapshot, they all will get restored by the custom component in line 101.
Note: To look at the custom component sources, export the FN Pasta Alfredo With Login skill and unzip the downloaded zip file. You can then browse to a folder that contains a .tgz file. Unzip the tgz file to access the custom component sources
Note: A sensible improvement to the snapshot component used in this example would be to add a timestamp to the snapshot. This way you could e.g. ignore and clean-up snapshots that exceed a specific idle time.
And finally, the order pasta skill uses a System.Switch component state to resume navigation.
Download and Run The Demo
This article had so much to say, which probably is easier to understand by having a look at the example. You import the ZIP file you can download from the link below as a digital assistant. Then, open the digital assistant and train the model if needed. Open the conversation tester for digital assistant and type I want to order pasta. Just follow the instructions in the conversation to explore the end-to-end example. If you are familiar with Oracle Digital Assistant then you would know how to skip prompts e.g. by typing I want to order a pasta bacon. Make it large and put garlic on.
Related Content
Product documentation: call a skill from another skill
Product documentation: Working with skill parameters
Product documentation: user scope variables
TechExchange: All 2-Minutes Oracle Digital Assistant Tech Tip Videos on YouTube