Rasa Core: FormAction: Cannot access slots in the follow-up `utter_ask_SLOT`

Hey there,

so I successfully used the sexy rasa core FormAction’s and I love em! :slight_smile: There is just this small problem I have which I was not able to figure out myself yet: Given I have two required_slots, lets call them forename and surname, I utter_ask the user for his forename.

He names it, it get’s extracted successfully and now I want to use it in my utter_ask_surname like so: - text: Thanks {forename}. What about your surname? where forename gets substituted with None… does anyone have an idea why this is the case and how I can access the slot right away?

Kind regards,

-Thomas

1 Like

FYI my FormAction does look like this:

class TestFormAction(FormAction):
"""Example of a custom form action"""
RANDOMIZE = True

def name(self):
    # type: () -> Text
    """Unique identifier of the form"""

    return "action_test_form"

def slot_mapping(self):
    # type: () -> Dict[Text: Union[Text, Dict, List[Text, Dict]]]
    """A dictionary to map required slots to
        - an extracted entity
        - intent: value pairs
        - a whole message
        or a list of them, where the first match will be picked"""

    return {
        'forename': [
            self.from_entity(entity='forename'),
            self.from_text(intent='get_forename'),
        ],
        'surname': [
            self.from_entity(entity='surname'),
            self.from_text(intent='get_surname'),
        ],
    }

@staticmethod
def required_slots(tracker):
    # type: (Tracker) -> List[Text]
    """A list of required slots that the form has to fill"""

    return ['forename', 'surname']

def submit(self, dispatcher, tracker, domain):
    # type: (CollectingDispatcher, Tracker, Dict[Text, Any]) -> List[Dict]
    """Define what the form has to do
       after all required slots are filled"""

    # utter submit template
    dispatcher.utter_template('utter_data_full_name', tracker)
    return []

Thanks for asking this question, actually I believe there might be a bug, but I’m not sure yet. Do you mind creating an issue in rasa_core_sdk repo?

1 Like

I am also on it to find out why this is the case. Hopefully I can come up with a PR, so far I’ll issue my findings :+1: Thanks for your answer, I was quite unsure if it was me or the SDK. :blush:

You are more than welcome to submit the PR. I believe that the source of the problem is that dispatcher.utter_template in rasa_core_sdk: rasa_core_sdk/executor.py at 47106d959767148d15b328a3a38a95cd697e0616 · RasaHQ/rasa_core_sdk · GitHub doesn’t actually use the tracker passed to it to update the message

So the slots need to be passed to the tracker on the CustomAction server side? I’m not sure if that’s the case but I’ll look into it!

the slots are already passed to the tracker, but the message doesn’t get updated with them

It looks to me as if the response from rasa_core_sdk custom action server is correct… so there must be something wrong with rasa_core?

FYI this is the json attribute from the resp variable in the image.

Alright, I found the issue and well, it was my fault! I’m super sorry but want to share my findings with you:

The actual problem did stem from MY domain.yml which made this particular piece of code not set the slots in the instant they were extracted… simply had to change from:

  forename:
    auto_fill: false
    type: rasa_core.slots.UnfeaturizedSlot
  surname:
    auto_fill: false
    type: rasa_core.slots.UnfeaturizedSlot

to this one

  forename:
    auto_fill: true
    type: rasa_core.slots.UnfeaturizedSlot
  surname:
    auto_fill: true
    type: rasa_core.slots.UnfeaturizedSlot

Until now, I was not fully sure about the function of the auto_fill. :slight_smile:

Thanks for the excellent support @Ghostvv !

SOLVED !

ah, no, that’s different problem, if you use forms, I strongly suggest to set auto_fill to false

Could you please try rasa_core_sdk branch tracker-updated-utterance with your old domain auto_fill: false?

Did as you asked @Ghostvv . It works! Solely the line Comparing master...tracker-updated-utterance · RasaHQ/rasa_core_sdk · GitHub does raise an error as there is no update method for the temp_tracker of type Tracker. Though, the rasa_core Tracker has such a method. :slight_smile:

oh, true, updated the branch to old code in this place

Nevertheless, I think it might be good to take from the “original” Tracker from the rasa-core repo for consistency reasons, right?

Also disambiguates the understanding of the class / object as they are supposed to be the same (while their implementation as of now is not identical).

well… yes, but sdk events are just dictionaries that do not contain apply_to method that is used by tracker.update

they are not really the same, sdk version is kind of serialized version of core classes

Hey, is this solved? I experience the same issue - got a FormAction, the slot returns None upon calling it in utterance. Actually it just gets set to the correct value one utterance too late, in online training I can see it is set to the actual slot value one step later: Should be setting slot here, but as you can see userid: None

Please enter the new userid! (Only the characters of the userid.)
      action_listen 1.00
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                                                                                      DFG44lksd@kfk5
                                                                                               intent: newuserid 0.63


Current slots:
        email: ppdls@mail.com, isconfirmed: None, userid: None, requested_slot: userid

And here it is all fine, but too late for my asking back:

userdetails_form 1.00
      slot{"userid": "DFG44lksd@kfk5"}
      slot{"requested_slot": "isconfirmed"}
      Do you confirm changing the userid to None for user ppdls@mail.com?
      1: yes
      (/choose{"isconfirmed": True})
      2: no (/choose{"isconfirmed": False})


Current slots:
        email: ppdls@mail.com, isconfirmed: None, userid: DFG44lksd@kfk5, requested_slot: isconfirmed

Now the userid is set, but as you can see, the utterance says “None”.

@Ghostvv, so I looked at this issue and according to the last comment I changed the request_next_slot() here to this in my actions.py:

dispatcher.utter_template("utter_ask_{}".format(slot), tracker, **tracker.slots)

Now it seems to work fine. If you agree, can this be updated in the code?

@lauraperge there is the branch tracker-updated-utterance with this fix, we’re looking into it, whether we want to merge this solution, or try something else

1 Like

I agree with @lauraperge : The current problem is in the definition of the dispatcher :

def utter_template(self,
    template,  # type: Text
    tracker,  # type: Tracker
    silent_fail=False,  # type: bool
    **kwargs  # type: Any
    ):
    # type: (...) -> None
    """"Send a message to the client based on a template."""

    message = {"template": template}
    message.update(kwargs)

    self.messages.append(message)

So you can pass the slots via the **kwargs and they will get updated in the message, but the utter_template function doesn’t read off the tracker directly. Right now, what the Dispatcher in rasa_core does is a bit involved to paste code here, but essentially there’s an NLG module sitting inside rasa_core, and the dispatcher’s utter_template function asks the NLG module to generate the message. Then the NLG takes the tracker and fills in the slots in the utterance.

If Rasa is going to move the Dispatcher to the rasa_core_sdk, there are three options that I see :

  • Move everything there and keep two copies of the NLG, which is a bit over-kill in my opinion

  • Find a way to communicate what the custom action tracked in the action server back to the bot, so that it keeps track of events and slots (so that in some sense, the action_server would compute and generate events, but not spit them itself to the bot

  • Only care about this particular issue and not the rest, and replace the dispatcher’s utter_template function by this one :

    def utter_template(self,
      template,  # type: Text
      tracker,  # type: Tracker
      silent_fail=False,  # type: bool
      **kwargs  # type: Any
      ):
      # type: (...) -> None
      """"Send a message to the client based on a template."""
    
      message = {"template": template}
      message.update(**tracker.slots)
      message.update(kwargs)
    
      self.messages.append(message)
    

where we just add the slots manually to the message in that function.