Is it possible to trigger event FollowupAction() from a Form validation method?

hi all,

I am using Rasa 2.8.15. I have a Form and using action.py to validate slots. For one of them, if intent == 'affirm', I want to trigger a FollowupAction() event. However because it is a slot validation method the returned object needs to be defined as a dictionary… how can I do it?

def validate_formslot(self, slot_value: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: DomainDict) -> Dict[Text, Any]:
        if tracker.latest_message['intent'].get('name') == 'affirm':
            return {"formslot": slot_value, [FollowupAction(action_name)]}

This does not work…

As you said, you cannot do it here.

What I suggest to do is setting a special slot:

def validate_formslot(self, slot_value, dispatcher, tracker, domain):
        if tracker.latest_message['intent'].get('name') == 'affirm':
            return {"formslot": slot_value, "followup": action_name}

Then, in the required_slots method, you return an empty list if the followup slot is set:

def required_slots(self, domain_slots, dispatcher, tracker, domain):
        if tracker.slots.get("followup") is not None:
            return []

        return domain_slots

Then, you write stories and a rule in which the followup slot is set while the form is active. And when that’s the case, the action gets executed :slight_smile:

- story: Execute followup from form
  steps:
  - intent: whatever
  - action: form_whatever
  - active_loop: form_whatever
  - slot_was_set:
    - followup: action_followup
  - slot_was_set:
    - requested_slot: null
  - action: action_deactivate_loop
  - active_loop: null
  - action: action_followup

- rule: Execute followup from form
  condition:
  - active_loop: form_whatever
  steps:
  - action: form_whatever
  - active_loop: null
  - slot_was_set:
    - followup: action_followup
  - slot_was_set:
    - requested_slot: null
  - action: action_followup
1 Like

thanks for suggesting @ChrisRahme. I dont understand how you can set "followup": action_name if the action_name has not been defined in the validation function? I also dont understand how the action gets executed if the return [ ] is empty? With your stories an action gets executed and I get out of the form, which I dont want to happen. I would like an action to be executed if an intent is recognized, and then keep filling the Form slots… let me know thanks

Define it :slight_smile:

You did not define it in your example, so I did not define it in mine.


You return [] to end the form, and then the action will be executed from stories.


You should have mentioned this from the start.

Why not execute the action from the required_slots() method then?

def required_slots(self, domain_slots, dispatcher, tracker, domain):
        if tracker.slots.get("followup") == 'action_test':
            dispatcher.utter_message('Write your action here')

        return domain_slots

thanks for suggesting @ChrisRahme very helpful. I think I have not been very clear, apologies. Your suggestion above will make the bot say 'Write your action here'in case the "followup" slot has a value of 'action_test'… but no custom action () gets executed if I understand correctly? The bot would then ask the user to fill the next domain_slot, instead of reacting to user response to the Action, right? I dont understand how to execute the action from the required_slots()?

1 Like

No worries :slight_smile:


All correct!


What’s not clear about it? You write your action in the if block instead of separately. For example:

def required_slots(self, domain_slots, dispatcher, tracker, domain):
        if tracker.slots.get('followup') == 'action_get_weather':
            location     = tracker.get_slot('location')            
            weather_info = getWeather(location)
            temperature  = weather_info['temperature']

            dispatcher.utter_message(f'The temperature is {temperature} degrees in {location}.').

        return domain_slots

Just make sure to set the slot to None again in the next validation method :slight_smile: Otherwise this will be executed every time.

Or, alternatively, you can do something like this (next_slot_name is the slot that will be filled next, and you’re checking it has not been filled):

if tracker.slots.get('followup') == followup_action_name and tracker.slots.get(next_slot_name) is None:

I will try to see if it works, thanks. My only concern is: the 'action_get_weather' gets triggered (meaning, bot says 'The temperature is {temperature} degrees in {location}.', and the user is not able to reply and have a different conversation flow, because we are including just the utter_message but the bot does not wait for user reply, it will prompt with the utter_next_slot (i mean the next slot to be filled).

Isn’t that what you want? You said yourself that the form should continue.

Anyway, I gave you all the basic possibilities. Try to learn by yourself and mix what I taught you according to your needs.

For example, you could execute that “action” in the required_slots method and return [], then go back to the form using a story…

There are so many possibilities, I will not and cannot showcase them all here - especially that you did not specify your use case, so there are lots of ways to interpret what you want to do.

Anyway, I gave you the building blocks and logic, you should be able to learn and modify this info according to your needs.

Good luck :slight_smile:

will try use these building blocks yes, thansks. I think based on what I described and your advice the way to go is to use different stories.

1 Like