Version: Latest

Validating Slot Values

This guide covers the different ways you can validate slot values returned after a collect step in a flow. Simple validations can be defined in the flow step itself, while validations requiring external data are performed by a custom action.

Validating a Phone Number

Assume that your assistant has a flow allowing users to change the phone number associated with their account. Note that the description field of the collect step already provides information to the Command Generator about the desired format.

flows.yml
flows:
update_number:
description: allows users to update the phone
number associated with their account.
steps:
- collect: phone_number
description: 'an entire US phone number,
including the area code.
For example: (415) 555-1234 .
When setting as a slot use this format,
with brackets and a hyphen,
even if the user didnt type it that way.'
domain.yml
slots:
phone_number:
type: text
responses:
utter_ask_phone_number:
- text: "What is the new phone number?"

Validating a Slot Value's Format with a Condition

Rejections are a lightweight way to do simple validation of extracted slot values. Add a rejections field to your collect step to validate the phone number extracted by the LLMCommandGenerator, and to reject the value if it does not match. This example uses a regular expression, but you can use any condition.

flows.yml
flows:
update_number:
description: allows users to update the phone
number associated with their account.
steps:
- collect: phone_number
description: 'an entire US phone number,
including the area code.
For example: (415) 555-1234 .
When setting as a slot use this format,
with brackets and a hyphen,
even if the user didnt type it that way.'
rejections:
- if: not ( slots.phone_number matches "^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$")
utter: utter_invalid_phone_number

Remember to add a corresponding response to your domain to inform the user that their phone number wasn't collected successfully. Afterwards, the user will be asked for their phone number again.

domain.yml
responses:
...
utter_invalid_phone_number:
- text: "Sorry, I didn't get that. Please use the format (xxx) xxx-xxxx"

Validating a Slot Value Against a Database or API

If you need more advanced logic to decide whether to accept a slot value, you can use a custom action instead of a rejection. For example, you can use a custom action if you need external data to know if a slot value is valid. This example checks whether there is already another account associated with this phone number.

To do this, add an action step to your flow, with next conditions to handle the branching logic. First, create a custom action to call the API:

actions.py
from typing import Any, Text, Dict, List
from rasa_sdk import Action, Tracker
from rasa_sdk.events import SlotSet
from rasa_sdk.executor import CollectingDispatcher
class ActionCheckPhoneNumberHasAccount(Action):
def name(self) -> Text:
return "action_check_phone_number_has_account"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
new_number = tracker.get_slot("phone_number")
# Mock logic for deciding if a number is available.
# This is where you would call an API.
has_account = hash(new_number) % 2 == 0
return [SlotSet("phone_number_has_account", has_account)]

This example action uses the hash of the number to determine the outcome, so that you can use fixtures to write deterministic end-to-end tests.

And add a boolean slot called phone_number_has_account to your domain, along with a response to send in case the phone number is already associated with another account. Also add the name of the custom action to the domain:

domain.yml
slots:
...
phone_number_has_account:
type: bool
actions:
- action_check_phone_number_has_account
responses:
...
utter_inform_phone_number_has_account:
- text: "Unfortunately that number is already associated with an account."

Now, add a new step to your flow to call this custom action. Create a condition in the next field of this step to branch based on the phone_number_has_account slot. If the number already has an account, your assistant will inform the user, unset the phone_number slot, and return to the start of the form. In order to jump back to the beginning of the form, add an "id" field to the first step in the flow. Your flow should now look like this:

flows.yml
flows:
update_number:
description: allows users to update the phone
number associated with their account.
steps:
- id: "collect_phone_number"
collect: phone_number
description: 'an entire US phone number,
including the area code.
For example: (415) 555-1234 .
When setting as a slot use this format,
with brackets and a hyphen,
even if the user didnt type it that way.'
rejections:
- if: not ( slots.phone_number matches "^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$")
utter: utter_invalid_phone_number
- action: action_check_phone_number_has_account
next:
- if: slots.phone_number_has_account
then:
- action: utter_inform_phone_number_has_account
- set_slots:
- phone_number: null
next: "collect_phone_number"