Exiting rasa form in the middle

So, I think I have this solved. There is a lot of old information in the forums about this so I am going to try to compile what works in 2.7 YMMV

First to exit a form, you do this during slot validation. Every slot has to have its own validation logic but as I have done, you can use a subroutine. I use 5 reflection slots (labeled reflection1 to reflection5) and then each runs a subroutine which does the same thing for each. For my form, if the user enters “done” in an empty slot, it will deactivate the form. Deactivation is currently very simple, you set

return {"requested_slot":None}

as indicated here. Below is my code in actions.py. I start the form using a rule, and then deactivate it as well which then runs a custom action. (see below). The one thing about my use case, which may be of interest to others, is that I wanted it to be that if the student had not fulfilled the minimum word requirement, it would allow them to continue adding to the form. That was a little tricky. Just restarting the form wouldn’t work. I needed to do two things in a custom action. Change the slot where they typed “done” to None, and then change the “requested_slot” slot to the name of that slot. If I just set the requested slot to the slot that had “done” it wouldn’t work (presumably because there was something already in it). So both steps were necessary to make it work. (code below)

Validation code

class ValidateReflectionForm(FormValidationAction):
    def name(self)-> Text:
        return "validate_reflection_form"

    def process_reflections(self, dispatcher: CollectingDispatcher,Tracker,slot_value) -> List[Text]:
        start_key="reflection"
        full_reflection=""
        for i in range(1,6):
            key=start_key+str(i)
            reflection=Tracker.get_slot(key)
            if reflection and reflection!="done":
                full_reflection+=reflection
        if slot_value.lower()=="done":
            return full_reflection
        return
    def validate_reflection1(self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        full_reflection=self.process_reflections(dispatcher,tracker,slot_value)
        if full_reflection:
            return {"reflection1":slot_value,"full_reflection":full_reflection, "requested_slot":None}
        else:
            return {"reflection1":slot_value}

    def validate_reflection2(self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        full_reflection=self.process_reflections(dispatcher,tracker,slot_value)
        if full_reflection:
            return {"reflection2":slot_value,"full_reflection":full_reflection, "requested_slot":None}
        else:
            return {"reflection2":slot_value}

    def validate_reflection3(self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        full_reflection=self.process_reflections(dispatcher,tracker,slot_value)
        if full_reflection:
            return {"reflection3":slot_value,"full_reflection":full_reflection, "requested_slot":None}
        else:
            return {"reflection3":slot_value}
    def validate_reflection4(self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        full_reflection=self.process_reflections(dispatcher,tracker,slot_value)
        if full_reflection:
            return {"reflection4":slot_value, "full_reflection":full_reflection, "requested_slot":None}
        else:
            return {"reflection4":slot_value}
    def validate_reflection5(self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        full_reflection=self.process_reflections(dispatcher,tracker,slot_value)
        if full_reflection:
            return {"reflection5":slot_value, "full_reflection":full_reflection, "requested_slot":None}
        else:
            return {"reflection5":slot_value}

rules.yml

- rule: start reflection
  steps:
  - intent: reflection_submit
  - action: utter_reflection_submit
  - action: reflection_form
  - active_loop: reflection_form
   
- rule: deactivate reflection form
  condition: 
  - active_loop: reflection_form
  steps:
  - action: reflection_form
  - slot_was_set: 
    - full_reflection: this is about robots
  - active_loop: null
  - action: action_process_reflections
  - action: utter_reflection_continue

reset form action code

lass ActionResetReflectionForm(Action):

    def name(self) -> Text:
        return "action_reset_reflection_form"

    def run(self, dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
        start_key="reflection"
        for i in range(1,6):
            key="reflection"+str(i)
            reflection=tracker.get_slot(key)
            if reflection=="done":
                next_slot=key
                print(f"reset requested_slot to {next_slot}")

        return [SlotSet("requested_slot",next_slot), SlotSet(next_slot,None)]
1 Like