Home / DialogFlow ES / DialogFlow tutorial: Setting context from your inline webhook using contextOut
DialogFlow ES

DialogFlow tutorial: Setting context from your inline webhook using contextOut

One of the nicest things about the new inline webhook editor in DialogFlow is that it allows people who create tutorials to make tightly focused ones instead of wrestling with getting their webhooks deployed.

The problem

A little while back I wrote a post about getting the user’s complete birthdate in DialogFlow. Turns out, the issue is somewhat non-trivial. Since DialogFlow will accept a date with only a month and a day (e.g. March 15th) as a valid input for the @sys.date entity, the user may not enter a year. The real issue, of course, is that DialogFlow will automatically append the current year as the year in the entered date. This is actually not missing information, but it is actually wrong information.

The date.partial field

One way to handle this is to get the user’s input as a @sys.date, and make the parameter value you extract to be $date.partial. Check out the link above to see a little animated gif which shows you how to do that. For now, I will proceed on the assumption that you have already done that.

Validation on the webhook

At this point, we will be validating the input to check if the $date.partial captured the full date or only a partial date. If it captures a partial date, then DialogFlow will send a message to the user asking for the date. On the other hand, if it captured the complete birthday, DialogFlow will simply send a message prompting for the next response.

The flowchart

As I mentioned in previous posts, I suggest creating flowcharts for your chatbots using XMind.

So here is the XMind flowchart which describes this flow. You can take a look at this article to understand the conventions I use in the flowchart.

Notice that the next input we wish to get is the user’s first name. Usually the way we drive such a conversation in DialogFlow is by setting a context with an appropriate name.

Naming convention for a context which indicates that user’s input is expected

As a little side note, I have a suggestion for how to name a context when you expect a value from the user. Call it “expecting_parametername” or “awaiting_parametername”.

Suppose you want to get the user’s first name. The usual convention is to simply give the context a name such as “parametername”, in this case, “firstname”. The challenge with that approach is that you cannot glance at an intent and immediately tell whether the parameter has already been collected, or if you still need to collect it.

On top of that, if you explicitly use “expecting_firstname” or “awaiting_firstname” or a similar prefix, you can use the same context as the input context for the corresponding fallback intent (that is, the user’s input didn’t match what you were expecting) and the context will remain meaningful. If you merely used the context “firstname” it will become quite confusing at that point.

Another good reason to prefix your context names like this is – your active contexts are supposed to represent the state of your system. (And I just realized that that is one more reason to always use a context lifespan of 1). Good naming of contexts can be an extremely useful tool as you try to reason about your chatbot behavior on a later date.

Defining the intents

So here is what our intents look like:

Intent 1: Default Welcome Intent

On the default welcome intent, the chatbot merely prompts for the user’s birthdate.

Intent 2: Get birthdate

And this is the intent which handles the birthdate input:

Note that I am using the $date.partial as the parameter value, and also that I am using the webhook for fulfillment.

Also notice that the output context is “expecting_firstname”. If the webhook code were to inspect its contexts coming in, it would have “expecting_firstname”.

Intent 3: Get Birth Year

We will also have an intent which gets only the birth year if the user forgot to supply it:

Intent 4: Get First Name

And finally, once the full birth date has been collected, the dialog moves to the next state for collecting the first name. Here is the intent which captures the first name:

Webhook contexts – what goes in and what comes out

Now the flowchart I presented here is omitting an interesting detail. The right hand side flow (where the user doesn’t provide the year) is not something that is detected automatically by DialogFlow on its end. It is actually something which we can only find out on the webhook by inspecting the date and checking to see if the year is actually a number or it is just a string UUUU.

So there are two steps happening there, and I have sort of rolled the two into a single node in the flowchart (because it is much easier to read).

This is what the pseudocode looks like on the webhook:

if (date.year == 'UUUU') //not a valid year
   clear the incoming context expecting_firstname
   set the contextOut to expecting_yearofbirth
   response = 'What year?'
   return response
else
   response = 'What is your first name?'
   return response

As you might expect, as soon as DialogFlow thinks it captured a date, it is going to set the output context to ‘expecting_firstname’ because that is what we have specified in our intent. But that isn’t the final output context. We need to then clear the ‘expecting_firstname’ context and instead pass the ‘expecting_yearofbirth’ as the context by using the contextOut.

Another way to say the same thing: even if you see a particular output context inside the DialogFlow console for a specific intent, it is not necessarily what will be the eventual context value if the intent called a webhook. This is because the webhook may still clear out the already set context and replace it with its own. Of course, on most occasions, you would prefer to design your chatbot so that the webhook isn’t actually updating the context in this way. We have no option here, but I will write an article later about why you should avoid updating the context from the webhook if you can help it.

Updating the context from the inline webhook code

So this is what we need to do from the webhook code: if the user were to provide the full birthdate including the year, the inline webhook will not update the context. The intent which gets the first name (Intent 4) will be able to fire because the “expecting_firstname” context will be active.

On the other hand, if the user didn’t provide the full birthdate and omitted the year, the webhook needs to do three things:

  1. Set the outputContext coming from the webhook as “expecting_birthyear” (meaning intent 3 can fire)
  2. Make sure the message prompt sent to the user is “What year?” (it would have been “what is your first name?” if the webhook wasn’t called)
  3. Clear/unset the context “expecting_firstname” by settings its lifespan to zero

The code snippet below shows how we do this:

function sendBirthDateResponse (responseToUser, parameters, inputContexts) {
    let responseJson = {};
    console.log('Parameters:'+JSON.stringify(parameters));
    console.log('Input Contexts:'+JSON.stringify(inputContexts))
    if (parameters['date'].startsWith('UUUU')){
      responseJson.speech = 'What year?';
      responseJson.displayText = 'What year?';
      var contextStr = '[{"name":"expecting_yearofbirth", "lifespan":1, "parameters":{}},{"name":"expecting_firstname","lifespan":0,"parameters":{}}]';
      var contextObj = JSON.parse(contextStr);
      responseJson.contextOut = contextObj;
      console.log('Response:'+JSON.stringify(responseJson));
      response.json(responseJson);
    }
    else{
      responseJson.speech = 'Your birthdate is '+parameters['date']+'. What is your first name?';
      responseJson.displayText = 'Your birthdate is '+parameters['date']+'. What is your first name?';
      console.log('Response:'+JSON.stringify(responseJson));
      response.json(responseJson);
    }
  }

How should the webhook code for the birth year intent behave? The code snippet below shows how:

function sendBirthYearResponse (responseToUser, parameters, inputContexts) {
    let responseJson = {};
    console.log('Parameters:'+JSON.stringify(parameters));
    console.log('Input Contexts:'+JSON.stringify(inputContexts));
    //do something with the input - save birth year for e.g.
    responseJson.speech = 'What is your first name?';
    responseJson.displayText = 'What is your first name?';
    console.log('Response:'+JSON.stringify(responseJson));
    response.json(responseJson);
  }

As you can see, it doesn’t do much other than set the response text to “What is your first name?”. This is because the context “expecting_firstname” is already the output context for Intent 3. Quick note: the output context set by an intent will not be unset by your webhook code unless you explicitly do it by setting its lifespan to zero, like I did in the code snippet which handles the getBirthDate intent.

Conclusion

In summary, using the webhook to set/unset contexts is sometimes the only way to steer the conversation down the right path. It is particularly important when you need to do some kind of input validation that DialogFlow cannot do on its own.


This website contains affiliate links. See the disclosure page for more details. 
"The magic key I needed as a non-programmer"

The custom payload generator was the magic key I needed (as a non-programmer) to build a good demo with rich responses in DialogFlow Messenger. I've only used it for 30 minutes and am thrilled. I've spent hours trying to figure out some of the intricacies of DialogFlow on my own. Over and over, I kept coming back to Aravind's tutorials available on-line. I trust the other functionalities I learn to use in the app will save me additional time and heartburn.

- Kathleen R
Cofounder, gathrHealth
In this free course, I provide some tips for managing large Dialogflow ES bots without compromising on accuracy.

Similar Posts

20 Comments

    1. This question is too general to answer in a comment. You can search my website for specific help, or if it is urgent you can get in touch for paid 1-on-1 video consultation via my Services page.

  1. A useful post – thanks Aravind. One question (for now).

    As you say the last webhook function doesn’t do very much (sendBirthYearResponse). I can’t see what the point of it is to be honest as it doesn’t check anything and just sets up the output context and response to be the same as the Dialogflow intent ‘GetYearOfBirth’ could do – why use a webhook in this instance? Thanks.

    1. Good point!

      The main reason is that if you got a partial date in the first input, you will get the birth year as a separate value, which usually means the webhook will need to handle it a little differently (versus getting the entire value in a single parameter).

      Said another way, if you choose to omit the webhook function call at this step, you will still need to add some other logic downstream to see whether user entered full birthdate vs partial date + birth year. Quite often, you will see that it is better to handle it right away. Besides, what if the year entered is a negative integer? You will need some validation for that too, since there isn’t an entity to represent just the year alone in Dialogflow.

      You can also skip the webhook call, as long as you are clear about this distinction and can add the appropriate logic downstream.

  2. I have taken user input email from user and i am checking my user input to database consists of email or not .If database consists of email given by user then i will proceed to next intent using contexts but email doesn’t exists in database then i have to say thank you .How to solve this problem can you tell ?

    1. Perhaps I should have been more clearer, but the resource files are available as part of a paid course (now I have updated the post to indicate that).
      Having said that, everything you need to create the agent plus the intended behavior is mentioned in full detail in the tutorial itself. If you want to speed up your workflow a bit, the resource files can help.

  3. I’m setting context like this, but when a user is fast with his/her input, the input arrives before the context is set and therefore the next input is not mapped to the correct intent. Any idea, how i can wait for the context to be set?

    1. I don’t think there is an easy solution to this problem. You need to train your users to only type after they receive the response. If you control the user interface (e.g. website chatbot), you can also disable the input area until the response comes back.

      1. Thanks for your answer. I wait for the response from dialogflow, but still the same problem. It seems the processing takes to long.
        What i do is: Sending the request, wait for it with .then() and afterwards sending the message to the user, like “please provide your birth-year”. But still, sometimes the answer of the user arrives before the context was set?

        1. I am not sure I completely understand your question. If you are interested, you can get in touch for coaching via Skype (Services -> Get in touch).

  4. Hi Aravind,
    i am using javaclient to set a context and its parameters.
    I see that I can read it in the console, when I choose Text response.
    But how do i read the context and params, when the intent calls a webhook.
    I am using v2 for the req/resp format in the webhook.
    Can you please help?

    1. I think you might want to check out this article. The Java client is meant for integrations, and generally doesn’t have any need to know about context and params, which is actually handled by the webhook (sometimes there are exceptions though).

      Also, you can get in touch for 1-on-1 Skype coaching if you need urgent help (go to Services on the menu -> fill out the contact form).