Setting a Slot in default fallback whilst using "UserUtteranceReverted()"


In my default fallback action I am trying to set a slot value AND return back to the conversation. Why doesn’t the below set my Slot value?

return [SlotSet('safety_net_count', safety_net_count), UserUtteranceReverted()]



UserUtteranceReverted reverts everything after the user’s message - including setting the slot.

I don’t know if events (the list in return) are processed in order and if that order matters. If yes, try to to revert the utterance BEFORE setting the slot:

return [UserUtteranceReverted(), SlotSet('safety_net_count', safety_net_count)]

If this does not work, try to use ActionReverted() instead:

return [ActionReverted(), SlotSet('safety_net_count', safety_net_count)]

If this doesn’t work as well, please explain more about what you’re trying to do so I can know if there are other ways :slight_smile:

I suggest you also read this thread: Difference ActionReverted and UserUtteranceReverted.

Hi Chris,

I’m not at my desk at the moment but I can say for sure that swapping the order caused a very very strange experience in that the fallback action was called twice and my rules weren’t working any more. I’ll try the ActionReverted on my return.

I’m trying to build in some logic to drive a difference response to fallbacks after a succession of unknown inputs e.g. last 3 inputs drove a fallback response, offer a feedback form etc. I’m using the slot(s) to store the count of successive fallback responses.

That’s my thought anyway, using slots to store the count and negating the need to use an external key/value pair store.

Thanks Mark

1 Like

The ActionReverted didn’t work I’m afraid. However, after a walk and a bit of thought I’ve done it a different way.

I’ve decided to go back through the tracker and count the number of inputs and fallback action events and compare to a trigger number (I store as a slot using initial_value).

The code below only triggers when the last 3 inputs resulted in 3 action_default_fallback actions. Just need to do something a little more elegant now (maybe trigger a FollowUpAction to deactivate any forms etc.) when this occurs, meaning users do not get stuck in forms etc.



class ActionDefaultFallback(Action):
    """Executes the fallback action and goes back to the previous state
    of the dialogue"""

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

    async def run(
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict[Text, Any]]:

        # Count user inputs and fallbacks
        event_user_input_count = 0
        event_fallback_action_count = 0

        for e in reversed(tracker.events_after_latest_restart()):
            if e['event'] == 'user':
                event_user_input_count += 1
                # Only check back inputs needed to
                if event_user_input_count == tracker.get_slot('session_safety_net_trigger'):
            if e['event'] == 'action' and e['name'] ==
                event_fallback_action_count += 1

        event_fallback_action_count += 1  # Add 1 for this action as it is not in the tracker yet

        if event_user_input_count == event_fallback_action_count:
            # Do something


I wanted to suggest something similar! :slight_smile:

I was going to suggest using slots instead, but if your solution works I think it may be cleaner than mine :slight_smile:

Thanks Chris.

1 Like