ResponseSelector during FormAction

Hi everyone,

I have two questions regarding the title of this thread. Imagine the following story:

## status_form
* trigger_status_form
   - status_form
   - form{"name": "status_form"}
   - slot{"requested_slot": "permission"}
* iaachat
    - respond_iaachat
    - status_form
    - slot{"requested_slot": "fullname"}
   - form{"name": null}
   - action_restart
## status_form
* trigger_status_form
   - status_form
   - form{"name": "status_form"}
   - slot{"requested_slot": "permission"}
   - slot{"requested_slot": "fullname"}
* iaachat
    - respond_iaachat
    - status_form
    - slot{"requested_slot": "phonenumber"}
   - form{"name": null}
   - action_restart

The form guides the user through some questions regarding the status of an order. In between, I want the user to be able to ask any question he wants to ask and continue the form processing afterwards. Because I won’t know what the question of the user might be, I want to use the new ResponseSelector for “iaachat”. I have implemented everything, tested it and most of the time it works fine, except in two conflicting moments.


A sample dialogue could look like:

User : Hey I want to ask about the status of my order.

Bot : Okay, sure. I need to process personal data – are you okay with that?


Now the user currently would have four options:

  1. Yes” -> The form would proceed to the next step (due to slot mapping –> intent confirm –> True)

  2. No” -> The form would utter a template and return self.deactivate() (due to slot mapping –> intent Deny –> False)

  3. ChitChat” (Iaachat) ->

    • ResponseSelector wins intent ranking for Iaachat and triggers an utterance that utters the predicted response.
    • Form is still active, proceeds and asks for the slot again as a second utterance in the same response (utter_ask_slotname)
  4. ChitChat” (No known intent triggered) ->

    • Since the form is not able to extract the required slot, the fallback is triggered by the bot

To make point 3 work – to let the bot utter the ResponseSelector-prediction AND to let the user know that there is the slot yet to fill, I need to throw “ActionExecutionRejection”, which is done in the validate-method and looks like:

# extract requested slot
if slot_to_fill:
    slot_values.update(self.extract_requested_slot(dispatcher, tracker, domain))

    if not slot_values:
        # reject to execute the form action
        # if some slot was requested but nothing was extracted
        # it will allow other policies to predict another action
        raise ActionExecutionRejection(
            self.name(),
            "Failed to extract slot {0} "
            "with action {1}"
            "".format(slot_to_fill, self.name()),
        )
        return []

If I use this implementation, the bot works as expected in this situation. Imagine, that the user responds:

User : Where is your booth?

Bot: Our booth is in Hall 3. (Utterance by response selector due to ExecutionRejection)

Bot : I need to process personal data – are you okay with that? (Utterance by still active form slot)

User : Hey you dirty freak!!!

This would cause again an ActionExecutionRejection because the slot can’t be extracted but it will trigger the fallback-action since there is:

  1. No ResponseSelector-intentthat is valid
  2. The requested slot could not be extracted

My expectation is, that the bot instead sais:

User : Hey you dirty freak!!!

Bot : Sorry, I couldn’t extract any confirmation or rejection. Please repeat. (Utterance by template utter_wrong_slotname)

Bot : I need to process personal data – are you okay with that! (Utterance by still active form)


To make this work, I need to implement the validate method like this:

# extract requested slot
if slot_to_fill:
    slot_values.update(self.extract_requested_slot(dispatcher, tracker, domain))

    if not slot_values:
        # reject to execute the form action
        # if some slot was requested but nothing was extracted
        # it will allow other policies to predict another action
        dispatcher.utter_template("utter_wrong_" + slot_to_fill, tracker)
        return []

return self.validate_slots(slot_values, dispatcher, tracker, domain)

If I use this implementation, the bot would utter that it wasn’t able to set the slot and ask for it again. Why does he do that? Because I don’t throw the ActionExecutionRejection. Which is okay, because I don’t really want to reject it.

Currently, I solve this whole problem by using this implementation:

# extract requested slot
if slot_to_fill:
    slot_values.update(self.extract_requested_slot(dispatcher, tracker, domain))

    if not slot_values:
        # reject to execute the form action
        # if some slot was requested but nothing was extracted
        # it will allow other policies to predict another action
        dispatcher.utter_template("utter_wrong_" + slot_to_fill, tracker)
        current_intent = tracker.latest_message['intent'].get('name')
        if current_intent == 'iaachat':
            raise ActionExecutionRejection(
                self.name(),
                "Failed to extract slot {0} "
                "with action {1}"
                "".format(slot_to_fill, self.name()),
            )
            return []
        return []

return self.validate_slots(slot_values, dispatcher, tracker, domain)

Basically this checks if we got an ResponseSelector-Intent triggered and if so, we reject the form execution. If not, we utter to the user that we weren’t able to extract the wanted slot.

Question 1 : Is there a better solution to this?

Question 2 : Let’s say I want to give the user the opportunity to ask the Response-ChitChat(IaaChat) question during the whole FormAction . Do I really need to permutate the stories to reinsert * iaachat after every slot asked which means that I would end up with n storylines where n is the number of slots to ask for. Wouldn’t it be great to provide the opportunity to consolidate ChitChat-Response-Selector questions during FormProcessing with only one statement?

Regards Julian

Hi Julian, thank you for very thoughtful post.

Regarding the ActionExecutionRejection, I could think of several possibilities:

  1. I think your solution is valid, but then you’d need to add more intents to your if statement if you want to expand your bot.
  2. The other solution would be to check for requested slot in fallback action and utter_wrong_slotname there.
  3. Also, you could use from_text(not_intent='iaachat') to extract and validate the slot and then utter_wrong_slotname in validate_slotname method

Regarding your second question: What type is your requested_slot? If it is not categorical, you can create only one story with chitchat interruption

Hi @Ghostvv,

thanks for your kind words and thanks for your suggestions. Sometimes there are more possibilities than one could process :slight_smile: I think midterm I’d go with modifying the fallback_action as you suggested.

Regarding your question:

If you mean requested_slot itsself then I am using the default value since I am not specifying it in slots list. All other slots are of type unfeaturized. Am I getting you right, that then it would be enough to use this story:

## ask_incident_report
* ask_incident_report
  - incident_form
  - form{"name": "incident_form"}
* chitchat
  - respond_chitchat
  - incident_form
  - form{"name": null}
  - action_restart

to be able to ask at any time during slot requesting that chitchat-question? Because according to the docs, I still would have to permutate my stories and set the *chitchat after every requested slot!?

Regards Julian

yes this story should be enough