The difference between `validate_{form}` action and `{form}` action for `required_slots` function, and how can we change the `required_slots` function for the `form` action (not the `validate_{form}` action)?

I am currently trying to dynamically set the slot questions based on the intent that triggered the form. So if user triggers the form using intent_1, it should ask for slot slot_1, if using intent_2 then slot_2 should be requested by bot.

I am currently trying to work it around using requested_slots function in validate_{form} action, but apparently this is not the right way according the debug outputs. When form is activated, the chatbot triggers the {form} action which directly asks to fill slot_1 irregardless of the intent that triggered the form. Only after filling out the slot_1 the chatbot runs validate_{form} action, which then sets the required slots.

Following is the code:

# domain.yml
slots:
  slot_1:
    type: text
    influence_conversation: false
    mappings:
      - type: from_text
        conditions:
        - active_loop: custom_form
          requested_slot: slot_1
  slot_2:
    type: text
    influence_conversation: false
    mappings:
      - type: from_text
        conditions:
        - active_loop: custom_form
          requested_slot: slot_2
forms:
  custom_form:
    required_slots:
    - slot_1
    - slot_2

# rules.yml
- rule: Activate form
  steps:
  - or:
    - intent: intent_1
    - intent: intent_2
  - action: custom_form
  - active_loop: custom_form

- rule: Submit form
  condition:
  - active_loop: custom_form
  steps:
  - action: custom_form
  - active_loop: null
  - slot_was_set:
    - requested_slot: null
  - action: action_submit_custom_form

actions.py

class ValidateCustomForm(FormValidationAction):

    def name(self) -> Text:
        return 'validate_custom_form'

    async def required_slots(
        self,
        domain_slots: List[Text],
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
        ) -> List[Text]:
        '''A list of required slots that the form has to fill.'''

        logger.info('validate_custom_form - required slots - START')
     
        updated_slots = domain_slots.copy()
        last_intent = tracker.active_form.get("trigger_message", {})\
            .get("intent", {}).get("name", 'intent_1')

        if last_intent == 'intent_1':
            updated_slots.remove('slot_2')
        else: 
            updated_slots.remove('slot_1')

        logger.info(f'validate_custom_form - required slots - {updated_slots}')
        logger.info('validate_custom_form - required slots - END')

        return updated_slots

I am currently trying to understand how to make form action (or override the form) so that when triggered, it dynammically changes its required slots only then sets the requested slot. Currently the flow of chatbot is as follows:

1st flow:

  • user: intent_1
  • bot: triggers form action and asks for slot_1 (set as requested_slot)
  • user: some text
  • bot: triggers validate_custom_form and since slot_1 is set, triggers submit

2nd flow:

  • user: intent_2
  • bot: triggers form action and asks for slot_1 (set as requested_slot) - should request for slot_2
  • user: some text
  • bot: triggers validate_custom_form and requests for slot_2
  • user: some text
  • bot: triggers submit