Reminders and External Events

Reminders and External Events

The ReminderScheduled event and the trigger_intent endpoint let your assistant remind you about things after a given period of time, or to respond to external events (other applications, sensors, etc.). You can find a full example assistant that implements these features here.

Reminders

Instead of an external sensor, you might just want to be reminded about something after a certain amount of time. For this, Rasa provides the special event ReminderScheduled, and another event, ReminderCancelled, to unschedule a reminder.

Scheduling Reminders

Let’s say you want your assistant to remind you to call a friend in 5 seconds. (You probably want some longer time span, but for the sake of testing, let it be 5 seconds.) Thus, we define an intent ask_remind_call with some NLU data,

## intent:ask_remind_call
- remind me to call [Albert](name)
- remind me to call [Susan](name)
- later I have to call [Daksh](name)
- later I have to call [Anna](name)
...

and connect this intent with a new custom action action_set_reminder.

class ActionSetReminder(Action):
    """Schedules a reminder, supplied with the last message's entities."""
    def name(self) -> Text:
        return "action_set_reminder"
    async def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict[Text, Any]]:
        dispatcher.utter_message("I will remind you in 5 seconds.")
        date = datetime.datetime.now() + datetime.timedelta(seconds=5)
        entities = tracker.latest_message.get("entities")
        reminder = ReminderScheduled(
            "EXTERNAL_reminder",
            trigger_date_time=date,
            entities=entities,
            name="my_reminder",
            kill_on_user_message=False,
        )
        return [reminder]

Finally, we define another custom action action_react_to_reminder and link it to the EXTERNAL_reminder intent:

- EXTERNAL_reminder:
  triggers: action_react_to_reminder

where the action_react_to_reminder is

class ActionReactToReminder(Action):
    """Reminds the user to call someone."""
    def name(self) -> Text:
        return "action_react_to_reminder"
    async def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict[Text, Any]]:
        name = next(tracker.get_latest_entity_values("name"), "someone")
        dispatcher.utter_message(f"Remember to call {name}!")
        return []

Cancelling Reminders

Sometimes the user may want to cancel a reminder that he has scheduled earlier. A simple way of adding this functionality to your assistant is to create an intent ask_forget_reminders and let your assistant respond to it with a custom action such as

class ForgetReminders(Action):
    """Cancels all reminders."""
    def name(self) -> Text:
        return "action_forget_reminders"
    async def run(
        self, dispatcher, tracker: Tracker, domain: Dict[Text, Any]
    ) -> List[Dict[Text, Any]]:
        dispatcher.utter_message(f"Okay, I'll cancel all your reminders.")
        # Cancel all reminders
        return [ReminderCancelled()]

External Events

Let’s say you want to send a message from some other device to change the course of an ongoing conversation. For example, some moisture-sensor attached to a Raspberry Pi should inform your personal assistant that your favorite plant needs watering, and your assistant should then relay this message to you.

To do this, your Raspberry Pi needs to send a message to the trigger_intent endpoint of your conversation. As the name says, this injects a user intent (possibly with entities) into your conversation.

Getting the Conversation ID

The first thing we need is the Session ID of the conversation that your sensor should send a notification to. An easy way to get this is to define a custom action that displays the ID in the conversation.

class ActionTellID(Action):
    """Informs the user about the conversation ID."""
    def name(self) -> Text:
        return "action_tell_id"
    async def run(
        self, dispatcher, tracker: Tracker, domain: Dict[Text, Any]
    ) -> List[Dict[Text, Any]]:
        conversation_id = tracker.sender_id
        dispatcher.utter_message(
            f"The ID of this conversation is: " f"{conversation_id}."
        )
        return []

Responding to External Events

Now that we have our Session ID, we need to prepare the assistant so it responds to messages from the sensor. To this end, we define a new intent EXTERNAL_dry_plant without any NLU data.

class ActionWarnDry(Action):
    """Informs the user that a plant needs water."""
    def name(self) -> Text:
        return "action_warn_dry"
    async def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict[Text, Any]]:
        plant = next(tracker.get_latest_entity_values("plant"), "someone")
        dispatcher.utter_message(f"Your {plant} needs some water!")
        return []

Now, your assistant will respond to the external sensor with messages, updating you on necessary actions.