How to create infinite loop in story? (or solve my problem in different way)

Hi, I’m creating registration form after which user is asked if data is correct. My question is: how to handle situation like this

[chatbot]: is Michael your first name?
[user]: no
[chatbot]: provide it once again
[user]: Michael
[chatbot]: is Michael your first name?
[user]: no
[chatbot]: provide it once again
[user]: Michael
...
and so on

Right now my register story looks like this:

...
  - register_form
  - form{"name": "register_form"}
  - form{"name": null}
  - utter_ask_if_data_ok
* deny
  - utter_which_slot_is_wrong
* wrong_first_name
  - action_first_name_wrong     // reset first_name slot
  - register_form
  - form{"name": "register_form"}
  - form{"name": null}
  - utter_ask_if_data_ok
* affirm
...

So what if the user wats to change the name 10 times? Do I have to create 10 stories?

I did it with checkpoints like this:

## register path
* register_request
  - utter_start_register_form
  - register_form
  - form{"name": "register_form"}
  - form{"name": null}
  - utter_ask_if_data_ok
> are_slots_ok  

## affirm and register
> are_slots_ok
* affirm
  - utter_register_successful 
  - utter_can_i_do_anything_more
  - action_chat_restart

## deny
> are_slots_ok
* deny
  - utter_which_slot_is_wrong
* wrong_first_name
  - action_first_name_wrong
  - register_form
  - form{"name": "register_form"}
  - form{"name": null}
  - utter_ask_if_data_ok
> are_slots_ok

But is it the correct approach? I once read that “abusing chechpoints” is bad practice. Is there more “correct” way of creating loops?

We had a very similar case. You could try to do everything within the form using an extra slot called first_name_confirmed which will be asked before first_name if first_name is already set. Your utter_ask_first_name_confirmed would basically ask is {first_name} your first name?

I adapted our own code to your case, I think that should work like this in your form action. Didn’t test that code but it should be working with some adaptation:

def slot_mappings(self):
    return {
        "first_name_confirmed": [
            self.from_intent(intent="affirm", value=True),
            self.from_intent(intent="deny", value=False),
        ],
        "first_name": [
            self.from_entity(entity="PERSON"),
            self.from_text(),
        ],
    }

@staticmethod
def required_slots(tracker):
    if tracker.get_slot("first_name") is not None:
        return ["first_name_confirmed", "first_name"]
    else:
        return ["first_name"]

def validate_first_name_confirmed(self, value, dispatcher, tracker, domain):
    if value is False:
        # reset the first_name if it's not confirmed
        return {
            "first_name_confirmed": False,
            "first_name": None 
        }
    else:
        return {"user_full_name_confirmed": True}

def validate_first_name(self, value, dispatcher, tracker, domain):
        return {
            "first_name_confirmed": True, # confirm whenever we ask them
            "first_name": value
        }

Hope that helps Nicolas