You can actually use just 1 counter slot, and use a validation action on the last required slot to check and iterate it’s value. I pulled the basis for each customization directly from the Advanced Usage forms docs.
Responses are just to make it clear what step it’s on, you could customize these or make them custom actions as you need. Result is this conversation, code is below:
Your input -> /greet
welcome
Round 1: Proposed subjects are x,y,z, is that fine?
Your input -> /affirm
precontent pls affirm?
Your input -> /affirm
content pls affirm?
Your input -> /affirm
feedback pls affirm?
Your input -> /affirm
Round 2: Proposed subjects are x,y,z, is that fine?
Your input -> /affirm
precontent pls affirm?
Your input -> /affirm
content pls affirm?
Your input -> /affirm
feedback pls affirm?
Your input -> /affirm
Round 3: Proposed subjects are x,y,z, is that fine?
Your input -> /affirm
precontent pls affirm?
Your input -> /affirm
content pls affirm?
Your input -> /affirm
feedback pls affirm?
Your input -> /affirm
goodbye
domain.yml
intents:
- affirm
- greet
slots:
# None of the slots used to fill the form need to be featurized
proposed_subjects:
type: any
precontent:
type: any
content:
type: any
feedback:
type: any
counter:
type: any
initial_value: 1
forms:
feedback_loop:
proposed_subjects:
- intent: affirm
type: from_intent
value: yes
precontent:
- intent: affirm
type: from_intent
value: yes
content:
- intent: affirm
type: from_intent
value: yes
# we will use a validation method for `feedback` that increases the counter and resets slots if necessary
feedback:
- intent: affirm
type: from_intent
value: yes
actions:
- validate_feedback_loop
- action_ask_feedback_loop_proposed_subjects
responses:
utter_welcome:
- text: welcome
utter_goodbye:
- text: goodbye
# There's no `utter_ask` for proposed_subjects slot becuase
# the custom action `action_ask_feedback_loop_proposed_subjects` should be called instead
# this should do what your action `action_proposed subjects` was doing
utter_ask_feedback_loop_precontent:
- text: precontent pls affirm?
utter_ask_feedback_loop_content:
- text: content pls affirm?
utter_ask_feedback_loop_feedback:
- text: feedback pls affirm?
rules.yml
I didn’t add a second way to trigger the form since you didn’t list one, but you could add more rules that also trigger the form under other circumstances.
rules:
- rule: Welcome
# This rule only applies to the start of a session.
conversation_start: True
steps:
- intent: greet
- action: utter_welcome
- action: feedback_loop
- active_loop: feedback_loop
- rule: Feedback loop completion
condition:
- active_loop: feedback_loop
steps:
- action: feedback_loop
- active_loop: null # indicates form is completed
- action: utter_goodbye
actions.py
from rasa_sdk import Action, FormValidationAction
class FeedbackLoop(FormValidationAction):
def name(self):
"""Unique identifier of the action"""
return "validate_feedback_loop"
def validate_feedback(self, value, dispatcher, tracker, domain):
"""Check value of counter slot, reset all slots if counter is not at 3 yet"""
current_counter = tracker.get_slot("counter")
if current_counter < 3:
counter = current_counter + 1
iterate_slots = {"counter": counter}
for slot in ["proposed_subjects", "precontent", "content", "feedback"]:
iterate_slots[slot] = None
return iterate_slots
elif current_counter == 3:
feedback = tracker.get_slot("feedback")
return {"feedback": feedback, "counter": 1}
## You can create custom actions like the one below to ask for other slots too if they need to vary e.g. per iteration
class ActionAskFeedbackLoopProposedSubjects(Action):
def name(self):
return "action_ask_feedback_loop_proposed_subjects"
def run(self, dispatcher, tracker, domain):
# your logic for proposed subjects goes here
# as a mock test I'll use the counter slot
count = tracker.get_slot("counter")
dispatcher.utter_message(text=f"Round {count}: Proposed subjects are x,y,z, is that fine?")
return []