Avoid repeat question after form interruption

I have a form with slot validation in which the bot asks the users questions. To some of these questions, the user might answer “I’m not sure/I don’t know”. In these cases, I would like to skip to the next question in the form, but can’t figure out how to do this.

My form:

example_form:
    required_slots:
    - action
    - colour

Example slot:

action:
    type: text
    mappings:
    - type: from_entity
      entity: action
    - type: from_text
      not_intent: unsure
      conditions:
      - active_loop: example_form
        requested_slot: action

Example rule:

  - rule: Unhappy path in example form
    condition:
    # Condition that form is active.
    - active_loop: example_form
    steps:
    # This unhappy path handles the case of an intent `unsure`.
    - or:
      - intent: unsure
      - intent: deny
    - action: utter_unsure
    # Return to form after handling the `unsure` intent
    - action: example_form
    - active_loop: example_form

My actions (excerpts):

class ActionUnsure(Action):
    def name(self) -> Text:
        return "action_unsure"

    def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> List[EventType]:


        if tracker.get_intent_of_latest_message() == "unsure":
            dispatcher.utter_message(
                reponse="utter_unsure"
            )

[.......]

Class ValidateExampleForm(FormValidationAction):
    def name(self) -> Text:
        return "validate_example_form"
    
    def validate_action(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        """Validate `action` value."""
        
        action = slot_value

        if action =="driving":
            dispatcher.utter_message(response="utter_example_form_action_driving")
        elif tank_what =="flying":
            dispatcher.utter_message(response="utter_example_form_action_driving")
        elif tank_what =="eating":
            dispatcher.utter_message(response="utter_example_form_action_eating")
        return {"action": action}

I’d like the conversation to go like this:

Bot: "What is X doing?"
User: "He is flying"
Bot: "What colour is the sun?"
User: ...

and if the user doesn’t know:

Bot: "What is X doing?"
User: "I don't know"
Bot: "That's fine, let's move on to the next question."
Bot: "What colour is the sun?"
User: ...

What is happening right now:

Bot: "What is X doing?"
User: "I don't know"
Bot: "That's fine, let's move on to the next question."
Bot: "What is X doing?"
User: stuck in a loop

I basically need a way to say, if the user doesn’t know the answer to a question, then let’s be OK with that and move on to the next slot. Surely there must be a way to do this?

In the slot validation you could get the intent prediction from the tracker and set the slot if the prediction is deny or similar intents.

@stephens can you explain a bit further? I tried putting it into the form validation function for validate_action but it doesn’t seem to grab the intent and I’m not sure how to debug. I’m thinking maybe it’s not the right place to put it as it would make sense to have it globally somewhere so every time the user utters “unsure”, the slot in question is filled and then skipped.

Here’s some example code.

Thanks. This is how I ended up solving it:

def validate_action(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        """Validate `action` value."""

        intent = tracker.latest_message["intent"].get("name")
        if intent == "deny" or intent == "unsure":
            dispatcher.utter_message(response="utter_unsure")
            return [SlotSet("action", intent)]
        
        if action =="driving":
            dispatcher.utter_message(response="utter_example_form_action_driving")
        elif tank_what =="flying":
            dispatcher.utter_message(response="utter_example_form_action_driving")
        elif tank_what =="eating":
            dispatcher.utter_message(response="utter_example_form_action_eating")
        return {"action": action}

I’m still putting it into every single validation method prior to the actual validation for lack of knowing a more efficient way to do it, but it works.