How to revert a form with all slots?


Imagine this story and domain. If the user decided to stop filling the form I would like the bot to forget the form and slots that might have been set and return to state where it uttered “utter_ask_something” as if nothing happened.

If I deactivate the form, bot will continue executing the story, which is not what I want.

Also, if possible, I would like to do that programmatically instead of writing a story for that because I have quite a lot of forms.


  - text: "What to do?"
      - title: "Start form A"
        payload: "/start_form_A"
      - title: "Start form B"
        payload: "/start_form_B"

* start_form_A
  - form_A
  - form{"name": "form_A"}
  - form{"name": null}

* start_form_B
  - form_B
  - form{"name": "form_B"}
  - form{"name": null}

I use a function for this purpose:

def kill_form(obj, next_intent):
    Force the end of a form and move on to the intent `next_intent`

    return obj.deactivate() + [ActionExecuted('action_listen')] + [UserUttered('/' + next_intent, {
        'intent': {'name': next_intent, 'confidence': 1.0},
        'entities': {}

The function will deactivate the form and set the next intent to whatever you pass on in the function parameters. You can return the values from a function such as request_next_slot in your form class.

After much trial and error I figured out how to do that.

This code achieves exactly what I want: completely forget that a form was executed, revert all slots and bot will reply last message before form was activated. I can say for sure that this works because next intents and being predicted by AugmentedMemoizationPolicy and not TED, therefore the stories are being followed exactly as if nothing happened.

def revert_form(
  tracker: "Tracker",
  dispatcher: "CollectingDispatcher"
  tracker_events = tracker.events_after_latest_restart()

  form_start = tracker.get_last_event_for("form")
  form_start_index = tracker_events.index(form_start)
  user_utterances_count = 1
  for ev in tracker_events[form_start_index:]:
    if ev["event"] == "user":
      user_utterances_count += 1

  return [
    UserUtteranceReverted() for i in range(user_utterances_count)
  ] + self.deactivate() + [