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)]