Defining conditions and responses

A dialog is made up of nodes, which are represented in the UI as boxes. Each node has two parts: a condition and a response.

Creating dialog nodes

You can also give each node a name. This makes it easier for you to remember the node's purpose and to locate the node when it is minimized. If you don't enter a name, the condition is used. If you do give names to your dialog nodes, each name must be unique.

The number of dialog nodes you can create in a single service instance depends on your service plan:

Service plan Dialog nodes per service instance
Standard/Premium 100,000
Free 25,000
  1. To open the dialog builder and create dialog nodes and branches, choose Dialog in the navigation bar. If Dialog is not visible, click Build from the navigation menu to open the page.
    When you open the dialog builder for the first time, the following nodes are created for you:

    • Welcome: The first node. It contains a greeting that is displayed to your users when they first engage with the bot. You can edit the greeting.
    • Anything else: The final node. It contains phrases that are used to reply to users when their input is not recognized. You can replace the responses that are provided or add more responses with a similar meaning to add variety to the conversation. You can also choose whether you want the bot to return each response that is defined in turn or return them in random order.
  2. To add more nodes to your dialog tree, use the Add node link Add node on an existing node.

    • To create a peer node (also called a sibling node), select the link below an existing node. A peer node is an alternative to the existing node; it is checked next if the condition for the existing node is not met.
    • To create a child node, select the link on the side of an existing node. A child node is processed after its parent node.

    As you create dialog branches, you can minimize the view of the branches that you have already created, in order to simplify the display and help you focus on the new branch. To minimize a branch, select the minimize icon Minimize icon in its base node.

Moving a dialog node

Each node that you create can be moved elsewhere in the dialog tree.

You might want to move a previously created node to another area of the flow, to change the conversation. You can move nodes to become siblings or peers in another branch.

  1. On the node you want to move, select the the Move icon Move icon.
  2. Select where you want to move this node. Two icons appear on the destination node. You can choose to place the node that you are moving as a peer to this node, or as a child of it.
  3. Choose one of the icons. Depending on which you choose, the source node is moved to appear as a peer or a sibling of the target node and is used in that branch during a conversation.

Defining conditions

The condition portion of a dialog node determines whether that node is used in the conversation. You can use any combination of intents, entities, context variables, and special conditions in the condition portion of a node.

Valid expressions in conditions are written in the Spring Expression (SpEL) language. For more information, see Spring Expression Language (SpEL) language. You can also use various shorthand notations to refer to intents, entities, and context variables; see Shorthand syntax.

  • The simplest condition is a single intent, which means that the node is used if the user's input maps to that intent. To check the presence of a particular intent in a condition, enter the name of the intent, preceded by a number sign, for example, #weather.

  • When you create a node, and you edit the condition, you might find that you need to define an intent that you do not yet have. You can choose to create the intent while editing the condition. Then, when you go to the Intents panel, the new intent appears in the list. Be sure to add some examples so that the intent can be recognized.

  • To check for a particular value for an entity, add the entity name, preceded by @, followed by a colon and the value, for example, @appliance:heat. Be sure to use a value and not a synonym.

    You might want to define a node that is used whenever any value is found for a particular entity. You can state this condition as @entity_name. This condition is satisfied if any value or synonym for the named entity is recognized in the user input. Be sure to create a peer node to handle the case where no value is recognized.

    As an alternative to the @appliance:(air conditioner) format, you can use @appliance == 'air conditioner'. When you use == you are evaluating only the value of the first detected @appliance entity only. Using @appliance:(air conditioner) gets expanded to entity['appliance'].contains('air conditioner'), which matches whenever there is at least one @appliance entity of value 'air conditioner' detected in the user input.

  • To use a context variable in your condition, use the format $variable_name:value or $variable_name == 'value'. The value of the condition might have been set by the application, or in the response portion of a previous dialog node.

  • The following special conditions are available:

    • anything_else: You can use this condition at the end of a dialog, to be processed when the user input does not match any other dialog nodes. The Anything else node is triggered by this condition.
    • conversation_start: Like welcome, this condition is evaluated as true during the first dialog turn. Unlike welcome, it is true whether or not the initial request from the application contains user input. A node with the conversation_start condition can be used to initialize context variables or perform other tasks at the beginning of the dialog.
    • false: This condition is always evaluated to false. You might use this at the top of a branch that is under development, to prevent it from being used, or as the condition for a node that provides a common function and is used only as the target of a Jump to action.
    • irrelevant: This condition will evaluate to true if the user’s input is determined to be irrelevant by the Conversation service.
    • true: This condition is always evaluated to true. You can use it at the end of a list of nodes or responses to catch any responses that did not match any of the previous conditions.
    • welcome: This condition is evaluated as true during the first dialog turn (when the conversation starts), only if the initial request from the application does not contain any user input. It is evaluated as false in all subsequent dialog turns. The Welcome node is triggered by this condition. Typically, a node with this condition is used to greet the user, for example, to display a message such as "Welcome to our Pizza ordering app."

Note: When you check the value of a numeric variable, such as an entity or a context variable, make sure that the variable has a value. If a variable does not have a value, it is treated as having value 0 in a numeric comparison. If you check the value of a variable in a condition such as @price < 100, and the @price entity has a null value, perhaps because it has never been set, the condition is evaluated as true. To prevent the checking of null variables, use a condition such as @price AND @price < 100. This condition verifies that a value was found for @price and the value is less than 100. If @price has no value, this condition is evaluated as false.

You can use a regular expression to check for a string of a certain format. For example, suppose you want to see whether the user's input contains an eleven-digit number. You can use a condition like this: input.text.matches('^[^\d]*[\d]{11}[^\d]*$'), which will match only if there is an eleven-digit number in the input and no other digits elsewhere. Non-numeric text before and after the number is ignored. To find the matching string, you can use the String.find method, which is described in the Methods section.

  • You can combine any of these types of condition in a single node.

    For example, you might check whether the intent #turn_off is present AND the value of the @appliance entity is heat. That node would be used, and its response returned, only if the user's input includes both the #turn_on intent and the heat value for the @appliance entity.

    To change the connector from and to or, select the and, and select or from the drop-down list.

  • You might want to combine nodes in order to use a combination of conditions. For example, when you recognize an intent, you might want to use another node to see whether an entity has been recognized. You do not need another user input before you look for the entity value. To combine conditions like this, you can use a Jump to action. In this case, no response is made to the user. Instead, the dialog is continued at another node that you choose.

    Tip: The process that is described here can be used and will work, but you can now provide multiple responses, each with its own condition, from a single node. See Multiple responses, described below.

    1. Create your first node with the initial condition (in this case, an intent) but do not specify a response.
    2. Create a child node that processes the second part of the condition (in this case, an entity).
    3. Return to the first node and from the edit view choose Jump to icon Jump to.
    4. Then choose the condition portion of the child node as the point from which to continue.

    You can see an example of this in the dialog portion of the Tutorial. The technique combines the #turn_on intent and the processing of entity values, and eliminates the user input that is ordinarily required between a dialog node and a child node.

Defining a response

In a response, you can perform any combination of these functions: update the dialog context; provide a text response to the user; and change the flow of the dialog by using a Jump to action. The three options are always processed in this order, regardless of the order in which you specify them.

If you want to provide a text response, and you do not need to update the context or change the flow, simply enter the response text in the Response portion of the node. If you want to change the flow, use a Jump to action, described below. If you want to update the context, follow these steps.

  1. Select the Advanced response icon to open a JSON editor in the response portion of the node.

  2. Enter the change that you want to make to the context, if any.

    To store the entire string that was input by the user, use input.text:

    {
      "context": {
        "repeat": "<?input.text?>"
      }
    }
    

    To store in a context variable the value of a string that you extract from the user's input by using a regular expression, use this syntax:

    {
      "context": {
         "number": "<?input.text.extract('^[^\\d]*[\\d]{11}[^\\d]*$',0)?>"
      }
    }
    

    To store the value of an entity in a context variable, use this syntax:

    {
      "context": {
        "place": "@place"
      }
    }
    

    To update an array in the dialog context, see Updating arrays.

  3. Enter the text that you want to return to the user, if any.

    To define output as a simple string, use this format to update value of the output.text property.

    {
      "output": {
        "text": "Hello $user"
      }
    }
    

    To define output as a JSON array, use this format:

    {
      "output": {
        "text": ["Hello there.", "How are you?"]
      }
    }
    

    To define output as a complex structured JSON object, use this format:

    {
      "output": {
        "text":{
          "values":["Hello.","Hi."],
          "selection_policy":"random",
          "append":false
        }
      }
    }
    

    If the text field of the output is a complex JSON object that contains a values attribute, selection_policy attribute, and an optional append attribute, an advanced mechanism processes this output.

    • values: A JSON array of strings that holds multiple versions of output text this dialog node can return. Which node is selected depends on the attribute selection_policy.

    • selection_policy: The following values are valid:

      • random: The system randomly selects output text from the values array and does not repeat them consecutively. For example, consider output.text that contains three values. For the first three times, a random value is selected but not repeated another time. After all the output values are given, the system randomly selects another value and repeats the process.

        {
          "output":{
            "text":{
              "values":["Hello.","Hi."],
              "selection_policy":"random"
            }
          }
        }
        

        The system processes this output.text property in this order:

        • The first time the node is hit the system randomly selects and delivers Hi. as the response.
        • The second time the node is hit the system selects and delivers Hello. as the response and resets the counter.
        • The third time the node is hit the system selects and delivers Hello. as the response.
      • sequential: The system delivers the first output text the first time the dialog node is hit, the second output text the second time the node is hit, and so on.

        {
          "output":{
            "text":{
              "values":["Hello.", "Hi."],
              "selection_policy":"sequential"
            }
          }
        }
        

        The system processes this output.text property in this order:

        • The first time the node is hit the system selects and delivers Hello. as the response.
        • The second time the node is hit the system selects and delivers Hi. as the response.
        • The third time the node is hit the system selects and delivers Hello. as the response.
    • append: When the attribute append is set to false, the output collected in previously executed dialog nodes is overwritten by the text value in this particular node.

      {
        "output":{
          "text":{
            "values": ["Hello."],
            "append":false
          }
        }
      }
      

      In this case, all other output text is overwritten by this output text.

      The default behavior assumes selection_policy = random and append = true. When the values array contains more than one item, then the output text is randomly selected from its elements.

By default, after making the specified response, your bot will wait for the user's next input. At the bottom of the edit view of the node, you see default next step. If you prefer, you can jump to a different node to continue the conversation. To change to a Jump to action, select the box that says Wait for user input and choose Jump to.... Then choose the node where the conversation should continue, as described below.

Jump to actions

When you want to change the flow of a dialog, use a Jump to action. This action tells the system which dialog node to go to next. Common uses are to bypass asking for user input when going to child nodes and to route the flow to a common dialog node from multiple locations in the tree. If you want to change the flow of the dialog by using a Jump to action, the target node must be created before you do so. To add a Jump to action to a node, select the box that says Wait for user input and choose Jump to....

Select a dialog node that the Jump to action targets and set whether the action targets the response or the condition of the selected dialog node or user input.

  • Response: If the statement targets the response part of the selected dialog node, it is run immediately. That is, the system does not evaluate the condition part of the selected dialog node and runs the response part of the selected dialog node immediately.

Targeting the response is useful for chaining several dialog nodes together. The response part of the selected dialog node is processed as if the condition of this dialog node is true. If the selected dialog node has another Jump to action, that action is run immediately, too.

  • Condition: If the statement targets the condition part of the selected dialog node, the service checks first whether the condition of the targeted node evaluates to true.
    • If the condition evaluates to true, the system processes this node immediately by updating the context with the dialog node context and the output with the dialog node output.
    • If the condition does not evaluate to true, the system continues the evaluation process of a condition of the next sibling node of the target dialog node and so on, until it finds a dialog node with a condition that evaluates to true.
    • If the system processes all the siblings and no condition evaluates to true, the basic fallback strategy is used, and the dialog evaluates the nodes at the top level too.
    • Note: the processing of Jump to actions changed with the February 3, 2017 release. Previously, if you jumped to the condition of a node, and neither that node nor any of its peer nodes had a condition that was evaluated as true, the system would jump to the root-level node and look for a node whose condition matched the input. In some situations this processing created a loop, which prevented the dialog from progressing. Under the new process, if neither the target node nor its peers is evaluated as true, the dialog turn is ended. Any response that has been generated is returned to the user, and an error message is returned to the application: Goto failed from node DIALOG_NODE_ID. Did not match the condition of the target node and any of the conditions of its subsequent siblings. The next user input is handled at the root level of the dialog. This update might change the behavior of your dialog, if you have Jump to actions that target nodes whose conditions are false. If you wish to restore the old processing model, simply add a final peer node with a condition of true and in the response use a Jump to action that targets the condition of the first node at the root level of your dialog tree.

Targeting the condition is useful for chaining the conditions of dialog nodes. For example, you might want to first check whether the input contains an intent, such as #turn_on, and if it does, you might want to check whether the input contains entities, such as @lights, @radio, or @wipers.

Chaining conditions helps to structure larger dialog trees.

Targeting user input requires a next user input before it is processed. This kind of targeting is helpful when you want to reroute the dialog tree evaluation to a particular part of the dialog tree for the next user input. When this statement is encountered by the system, the system returns an actual response, and in the next dialog round the system continues to evaluate from the dialog node that is targeted by this Jump to statement. It tries to match the condition first and the conditions of the siblings next. If no match is found, the evaluation continues at the top level of the tree.

Multiple responses

A single dialog node can provide several different responses. Each of the responses can be triggered by a different condition. This approach enables you to simplify your dialog tree.

The node still has a main condition, which is the condition for using the node and processing the conditions and responses that it contains. Let's look at an example.

In this simple example, we return to the cognitive car concept; we'll process the #turn_on intent and provide different outputs depending on the entity that we detect. We could use multiple dialog nodes to accomplish this, but we're going to do it in a single node. The main condition for the node is #turn_on, which means that the user has asked us to turn on an appliance in the car. To keep things simple, we'll focus on requests to turn on the heat or the air conditioning. Here are the steps we follow:

  1. Click the node to open the editing view.
  2. Let's give our node a name and call it Turn on. Naming a node makes it easier to remember its purpose and to find the node when it is minimized.
  3. Under "Triggered by", enter #turn_on as the condition for the node.
  4. Under "Fulfill with a response", select to add a condition, and enter @appliance:ac to check whether the user asked to turn on the air conditioning.
  5. Enter a response: A bit too warm? OK, turning on the @appliance. By using the entity name, we repeat the same value that the user entered. Here is our node so far, in the edit view: Turn_on node with first response
  6. Select Create another response. For the condition, enter @appliance:heat.
  7. For the response, enter Chilly, eh? Turning on the heat.
  8. Again, select Create another response. For this third entry, we don't need to check the appliance. If it's not AC or heat, we're not interested right now; we can come back and add other appliances later. For the condition, enter true. This causes the accompanying response to be used whenever this part of the node is reached. In fact, you could leave this condition blank; the conditions for individual responses within a node default to true. But it's a good idea to add the true condition to make the purpose clear.
  9. For the response, enter Please try again.
  10. Close the edit view of the node.

Now let's look at our node. It shows the number of responses that are defined (3), and it shows the three conditions and responses: Completed Turn_on node

This single node now provides the function that would have required four separate nodes if we hadn't used the multiple-response capability.

Tips:

  • The conditions within a node are evaluated in order, just as nodes are. Be sure that your conditions and responses are listed in the correct order. If you need to change the order, select a condition and move it up or down in the list using the arrows that appear.
  • If you want to update the context, you must do so in each individual response. There is not a common response section.
  • The Jump to action is processed after a response is selected and delivered. If you add a Jump to action, it is run after any response that is returned from the node.

Adding variety

If your users return to your bot frequently, they might be bored to hear the same greetings and responses every time. You can add variations to your responses so that your bot can respond to the same condition in different ways. You can add variations whether you are using one response or multiple responses in a node.

Let's add some variations to the responses that you just created.

  1. Select the node that you named Turn on to open the editing view. Find the first response that you added.
  2. Select Add a variation to your response.
  3. Enter another response to be used with the same condition, such as Cooling you off with the air conditioner.
  4. Repeat the previous step to add several variations if you wish.
  5. Add some variations to the responses for turning on the heat.

By default, responses are rotated sequentially, as if they were chosen from an ordered list. If you prefer that responses be returned randomly, select Set to random.

Updating arrays

If your dialog context data contains an array of values, you can update the array by appending values, removing a value, or replacing all the values.

Choose one of these actions to update the array. In each case, we see the array before the action, the action, and the array after the action has been applied.

  • Append: To add values to the end of an array, use the append method.

    For this Dialog runtime context:

    {
      "context": {
        "toppings_array": ["onion", "olives"]
      }
    }
    

    Make this update:

    {
      "context": {
        "toppings_array": "<? $toppings_array.append('ketchup', 'tomatoes') ?>"
      }
    }
    

    Result:

    {
      "context": {
        "toppings_array": ["onion", "olives", "ketchup", "tomatoes"]
      }
    }
    
  • Remove: To remove an element, use the remove method and specify its value or position in the array.

    • Remove by value removes an element from an array by its value.

      For this Dialog runtime context:

      {
        "context": {
          "toppings_array": ["onion", "olives"]
        }
      }
      

      Make this update:

      {
        "context": {
          "toppings_array": "<? $toppings_array.removeValue('onion') ?>"
        }
      }
      

      Result:

      {
        "context": {
          "toppings_array": ["olives"]
        }
      }
      
      • Remove by position: Removing an element from an array by its index position:

        For this Dialog runtime context:

      {
        "context": {
          "toppings_array": ["onion", "olives"]
        }
      }
      

      Make this update:

      {
        "context": {
          "toppings_array": "<? $toppings_array.remove(0) ?>"
        }
      }
      

      Result:

      {
        "context": {
          "toppings_array": ["olives"]
        }
      }
      
  • Overwrite: To overwrite the values in an array, simply set the array to the new values:

    For this Dialog runtime context:

    {
      "context": {
        "toppings_array": ["onion", "olives"]
      }
    }
    

    Make this update:

    {
      "context": {
        "toppings_array": ["ketchup", "tomatoes"]
      }
    }
    

    Result:

    {
      "context": {
        "toppings_array": ["ketchup", "tomatoes"]
      }
    }
    

More information

For information about the expression language used by dialog, plus methods, system entities, and other useful details, see the Reference section.