Way to bypass validate_{slot_name} method if slot is pre filled?

Hey,

Is there a way to bypass validate_{slot_name} method if that slot was prefilled in the form action and validate only if the slot value is being updated?

Thanks

@Bhanu could you clarify what you mean with an example?

Hi @akelad,

If I have slot A as a required slot in the form and I have defined method validate_A, then whenever the form runs, it will try to validate the slot A even if slot A was prefilled. I want form to validate the slot only if slot is getting updated inside the form and not when it was prefilled.

i don’t think there’s really a way to do that at the moment, no. What’s the reason you don’t want to validate it?

I am actually not using validate method just to validate the slot rather I am using it to update the slot by using multiple entities(latest) and if the slot was prefilled, the slots get updated using wrong entities.

can you show the code of the validation?

def validate_duration(self,
                            slot_dict: Dict[Text, Any],
                            dispatcher: CollectingDispatcher,
                            tracker: Tracker,
                            domain: Dict[Text, Any]
                            ) -> float:

    hr = next(tracker.get_latest_entity_values("duration_hour"), None)
    min = next(tracker.get_latest_entity_values("duration_minute"), None)
    if hr is not None and min is not None:
        temp = int(hr) + int(min) / 60
        return temp
    elif hr is not None and min is None:
        return int(hr)
    elif hr is None and min is not None:
        return int(min) / 60
    else:
        return tracker.get_slot("duration_sleep")

This is validation code for only one slot. Similarly, this type of code is used in other slots too. So for example if our last user input contains “duration_hour” and “duration_minute” and after that input our form gets activated and slot duration is lets say prefilled. Then in that case, the value of the slot will get updated using the latest entities which may not be same as the original ones.

Is there a better way to use multiple entities in combination to update a slot?

Not quite sure I understand this validation - it doesn’t seem to follow our standard validation format: Forms

You’re not using the value of the current slot you’re validating at all - does this code even run?

Yeah it was running with warning that returning values like this is deprecated. so, I had updated my code as:

def validate_duration(self, slot_dict: Dict[Text, Any], dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any] ) -> float:

    hr = next(tracker.get_latest_entity_values("duration_hour"), None)
    min = next(tracker.get_latest_entity_values("duration_minute"), None)
    if hr is not None and min is not None:
        temp = int(hr) + int(min) / 60
        return {"duration":temp}
    elif hr is not None and min is None:
        return {"duration":int(hr)}
    elif hr is None and min is not None:
        return {"duration":int(min)/60}
    else:
        return {"duration":value}

and as I already mentioned I am using validator not to validate rather to update values using multiple entities.

So, can I do this in some other way?

The validation function will run only if the slot is filled (either prefilled or filled inside form action). The validation function is supposed to validate the value that is filled in that slot. So merely updating the slot without checking it’s value is not the right way. But if you must override this behavior you can override the _activate_if_required method defined at rasa_sdk/forms.py. Here is the original definition:

async def _activate_if_required(
    self,
    dispatcher: "CollectingDispatcher",
    tracker: "Tracker",
    domain: Dict[Text, Any],
) -> List[EventType]:
    """Activate form if the form is called for the first time.

    If activating, validate any required slots that were filled before
    form activation and return `Form` event with the name of the form, as well
    as any `SlotSet` events from validation of pre-filled slots.
    """

    if tracker.active_form.get("name") is not None:
        logger.debug(f"The form '{tracker.active_form}' is active")
    else:
        logger.debug("There is no active form")

    if tracker.active_form.get("name") == self.name():
        return []
    else:
        logger.debug(f"Activated the form '{self.name()}'")
        events = [Form(self.name())]

        # collect values of required slots filled before activation
        prefilled_slots = {}

        for slot_name in self.required_slots(tracker):
            if not self._should_request_slot(tracker, slot_name):
                prefilled_slots[slot_name] = tracker.get_slot(slot_name)

        if prefilled_slots:
            logger.debug(f"Validating pre-filled required slots: {prefilled_slots}")
            events.extend(
                await self.validate_slots(
                    prefilled_slots, dispatcher, tracker, domain
                )
            )
        else:
            logger.debug("No pre-filled required slots to validate.")

        return events

You can easily manipulate the prefilled_slots dictionary of this method if you don’t want your prefilled slots to be validated.