Accessing previously-set slot values in current form action

I have a form action for three slots: A, B, C. I have validate functions for each: validate_A(), validate_B(), validate_C()

If I enter two sentences: “value for A, value for B” “value for C”

Then when validate_C() is executed, the slot values for A and B are available.

However, if I enter just one sentence: “value for A, value for B, value for C”

Then indeed it executes validate_A() and validate_B(), but when it executes validate_C(), the tracker.slots values for A and B still have None. It seems as if the slots are not set until all form slots for the current sentence are processed.

Does that sound right? If so, then what is the best way to update the tracker so the slot values for A and B will be visible to C?

What I am doing now is something probably pretty bad: I am just setting tracker.slots[‘A’] in validate_A() and tracker.slots[‘B’] in validate_B(). This makes these slot values available to validate_C() and solves my problem.

But I’m wondering if there is a more idiomatic way of doing this?

You’re right. The tracker is only updated after a complete run of the FormAction. After a complete run the FormAction returns SlotSet events for all slots, that have been set and the tracker is updated afterwards.

So far I dont know of any other solution other than you mentioned, but it would be nice to have a ‘real’ solution to the problem. What are you trying to do with the other slot values? In my case I want to validate multiple slots together even if theyre entered in arbitrary order.

It’s just a little currency conversion example. A=from_currency, B=to_currency, C=curr_qty, D=change_denomination.

so after they enter from_currency and to_currency and curr_qty, I want to calculate another value that I will stash in a non-form slot for later use outside the form.

Training data looks like:

- I need to get [USD](to_currency) from [Yuan](from_currency)
- convert [dollars](from_currency) to [yuan](to_currency)
- [Pounds](currency)

Here you can see I have from_currency, to_currency, and currency (when there are no predicates in the text).

## lookup:from_currency
  data/entities/currencies.txt

## lookup:to_currency
  data/entities/currencies.txt

## lookup:currency
  data/entities/currencies.txt

from slot_mappings():

    "from_currency": [self.from_entity(entity="from_currency", intent="currency_convert"),
                      self.from_entity(entity="currency", intent="currency_convert")],
    "to_currency": [self.from_entity(entity="to_currency", intent="currency_convert"),
                    self.from_entity(entity="currency", intent="currency_convert")],

This works fine for my scenario so far. The alternative I think is to just have 1 currency entity and write a bunch of code in validate that starts looking for special words before and after the entity (e.g., if I find “from” before currency entity, then put in from_currency, etc.) but that seems pretty horrible.

Grrrr, previously it seemed like it was reliably validating slots in order (from required slots) and now it seems random. Ugh.

Yep, it’s an iteration over a dictionary

Edit: tracker.latest_message gives you access to the intent and entities of last message. You could look there, if the slot is empty.

1 Like

Thanks… would be great if it were an ordered dictionary.

I can just isolate the logic that I currently have in C (which depends on slot values A and B) and then call that from A, B and C. But since the tracker doesn’t update slots until after the full FormAction is run (thx for confirming that btw), I need to stitch together existing slots with entities from the latest user response to cobble together what the post-FormAction slot values should look like.

Since the project calls for something like 100 of these scenarios/agents, I’ll try to create something reusable… unless there’s someway to order slot-filling validation without modifying rasa source.

Continuing the discussion from Accessing previously-set slot values in current form action:

I have a use case where Slot A is filled before slot B, but validation of Slot B depends on what value is in Slot A. I was trying to get the value of slot A in the validate_B method by using

tracker.get_slot("A") but it didn’t work. Using :

next(tracker.get_latest_entity_values("A"), None)) I was able to get the slot value for A which was set before the current slot and now I can use it to validate slot B

Yeah, I essentially did the same thing - created a latest_entity() function and overlaid it with the slot value in case it was set before. e.g.,

curr_A = next(tracker.get_latest_entity_values("A"), None)) or tracker.get_slot("A")

In your required fields is A before B?

def required_slots(tracker: Tracker) -> List[Text]:
		return ["A","B"]

For me it is and it works fine, I am guessing because the slots are checked based on the order given here

Yes, but users don’t always enter just one value at a time. Assume you have A, B, C. Even if you ask for A, sometimes they’ll say B, sometimes A and B, sometimes A and C, etc. That’s the nice thing about a Form - you can pick up these values as the user expresses them instead of forcing them to enter A then B then C, which becomes tedious.