Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for external triggers / asynchronous actions #3789

Closed
wochinge opened this issue Jun 14, 2019 · 14 comments · Fixed by #4095
Closed

Support for external triggers / asynchronous actions #3789

wochinge opened this issue Jun 14, 2019 · 14 comments · Fixed by #4095
Assignees
Labels
area:rasa-oss 🎡 Anything related to the open source Rasa framework type:enhancement ✨ Additions of new features or changes to existing ones, should be doable in a single PR

Comments

@wochinge
Copy link
Contributor

wochinge commented Jun 14, 2019

Motivation

There is currently no way to send a bot message to the user via an external API call.
This is e.g. useful

  • if an external sensor should trigger sth like an alert, which should result in a message to the user
  • if you have asynchronous action which should notify the user when they are finished.

Proposed Solution

When calling this endpoint (/conversations/{conversation_id}/execute) it should be possible to specify an output channel (either by name or latest) which the output of the action should be redirected to.

Now there are two cases of channels:

  • asynchronous ones (were we send a message to an endpoint (e.g. facebook) and they take care of getting it to the user)
  • synchronous ones (e.g. Rest), where the user usually sends a message and waits for the result. We have no way to directly contact the user, we have to wait until the user comes back

Asynchronous Channels:

In case of asynchronous channels we can create the input channel based on the credentials files (from_credentials) and call send_message (we have to make sure each asynchronous channel has such a method).

Maybe sth like:

channel_from_query = ...
channel = _create_single_channel(channel_from_query, credentials)
output = channel.get_output_channel()
if not output:
  # channel not supported since it's synchronous
else:
   output.send_response(...)

Synchronous Channels:

The question is how to handle synchronous channels. Either

  • don't support this functionality for them (easier, but not solved in a clean way imho)
  • store the bot messages with a flag "not retrieved" in the database (I think bot events are not featurized, right?) and look for "not retrieved" messages the next time the user comes back, and send these together with the results of the next call
  • have some sort of global in-memory buffer of the format Dict[sender_id, List[BotMessages]] whereby we have to ensure that a certain size of this buffer is not exceeded

I opt for not supporting synchronous channels, but giving the option to provide a webhook in credentials.yml which can be called.

Webhook in credentials.yml

Guess we could implement this as regular channel, which can only be used as output channel?

@wochinge wochinge added type:enhancement ✨ Additions of new features or changes to existing ones, should be doable in a single PR type:discussion 👨‍👧‍👦 Early stage of an idea or validation of thoughts. Should NOT be closed by PR. labels Jun 14, 2019
@tmbo tmbo added the area:rasa-oss 🎡 Anything related to the open source Rasa framework label Jun 25, 2019
@amn41
Copy link
Contributor

amn41 commented Jun 27, 2019

Thanks tobi- for the synchronous case can’t we assume the client will be polling for messages and will find the messages “sent” to the user?

@wochinge
Copy link
Contributor Author

will find the messages “sent” to the user?

where would the user find them? They could only poll the tracker and see whether there are unknown events. Or we store the "not yet found" messages somewhere.

@amn41
Copy link
Contributor

amn41 commented Jun 27, 2019

We might not be understanding each other.
In the rasa x UI the client polls the backend for new messages. There is no concept of “new” or “unseen” messages. Messages sent by an outside trigger would show up in exactly the same way

@wochinge
Copy link
Contributor Author

In the rasa x UI the client polls the backend for new messages.

But in this case the UI polls the tracker und checks if there are any new messages. That's not really elegant in my opinion.

@amn41
Copy link
Contributor

amn41 commented Jun 28, 2019

yes it's not v elegant, but this is also how the rasa x ui works currently

@wochinge
Copy link
Contributor Author

Ok. So you would not offer a webhook which they could specify?

@wochinge
Copy link
Contributor Author

wochinge commented Jul 8, 2019

@tabergma Please check if that's somewhat understandable:

So, the user is calling an endpoint and expects an actual bot response either via the api response or via a specific channel (which the user can specify in his request). Is that correct? Are external triggers then also calling this API? Maybe you can explain again

No. So you have three participants

  • a user chatting to the bot
  • the bot
  • some external event (let's call it trigger): this could e.g. be a sensor, some event ("your pizza is ready now")

Currently it's not possible to model the following case:

  1. user speaks to the bot (E.g. ordering a pizza)
  2. [something going on in between] (e.g. the user closes their app)
  3. An external event (trigger) calls an action on the current conversation of the user by doing an HTTP request to the Rasa API). This action leads to some BotUtterance events which should be communicated back to the user (e.g. "Pizza is ready")

@wochinge
Copy link
Contributor Author

wochinge commented Jul 8, 2019

How would you deliver a message to, say, the rest channel, given that there's no open request?

@ricwo
I wouldn't. Users can either use Alan's suggestion from #3789 (comment) or we add some webhook channel. A webhook channel would be:

  • A channel which has no implementation for the input, but only for the output channel
  • it would use sth like request.post(message) to call a endpoint of choice which then the user's could use to forward messages to their users

@wochinge wochinge self-assigned this Jul 23, 2019
@wochinge wochinge removed the type:discussion 👨‍👧‍👦 Early stage of an idea or validation of thoughts. Should NOT be closed by PR. label Jul 23, 2019
@wochinge wochinge mentioned this issue Jul 24, 2019
5 tasks
@darkblueorange
Copy link

Hello guys
Thanks for this really cool feature, triggering /conversations/{conversation_id}/execute is a very nice hack for asynchronous notifications.

TLDR => go to [TLDR bug] and [TLDR solution]
In our use case though, we seem to have some kind of issue (but we finally managed in some way to get around). I'll try to explain as clearly as I can :
1- User discuss with RASA bot, asking for some business/personal need, let's say "leave vacation"
2- RASA call at some point SDK server, itself calling some workflow stuff verifying availability/stock ...
3- Workflow creates an ID for the instance, sending it back to User => this scenario is working as it is still in the flow of the conversation designed
3bis- Workflow also wants to send the notification to User's manager. Besides the point that with Facebook Messenger this is a pain (Messenger doesn't like to have a bot proactively initiating some conversation, even if it's just idle for some "too long" time), we manage to send this "curl equivalent" via REST API and call RASA :

curl -X POST http://localhost:5005/conversations/{TrackerID}/execute?output_channel=callback \
-H 'Content-Type: application/json' -d '{"name":"utter_ask_manager", "policy":"string", "confidence":"0.987232"}'

Our real problem though is in the manager's conversation (sorry for this long introduction) :

Let's say utter_ask_manager looks like this in domain.yml :

utter_ask_manager:
    - text: "Hello, your employee {employee_name} ask for a leave. Do you validate ?"
      buttons:
      - title: "Yes"
        payload: /mng_validate_demand{"ent_mng_validation":"yes"}
      - title: "No"
        payload: /mng_validate_demand{"ent_mng_validation":"no"}

As this notification arrives "from nowhere" (or more likely from "nowhen"), we struggle a bit to figure out how to design it. Should we begin by - utter_ask_manager ? or by * mng_validate_demand ?
Anyway whatever we tried there we didn't manage to have a satisfying expected behaviour with only this yet.

Let's assume this story description :

## validate_path
* mng_validate_demand{"ent_mng_validation":"yes"}
    - slot{"ent_mng_validation":"yes"}
    - utter_mng_received_validation
    - action_mng_leave_validation

[TLDR bug]
RASA does recognise the intent, but doesn't know what to do with it. We keep seeing in the logs "There is no memorised next action". Predicted action is action_listen whatever we try (we tried also with triggers and MappingPolicy, that is a very cool stuff btw).

Funny thing was : if we click twice => IT WORKS.
So by digging a little bit, we ended up in identifying that :
[TLDR solution]
If we do some :

curl -X POST http://localhost:5005/conversations/{TrackerID}/execute?output_channel=callback -H 'Content-Type: application/json' -d '{"name":"action_listen", "policy":"string", "confidence":"1.0"}'

in the same time than we push utter_ask_manager towards the manager, ... then IT REALLY WORKS : the flow of the conversation can be predicted, and so on.

Soooo ... either we messed up in reading/finding/understanding documentation of the sequence of steps we had to do to send an action AND activate a working conversation behind, OR there's a weird thing going out there.

Our final analysis came by seing in the logs that the manager's Tracker was not in the good state for RASA to be able to predict next action, and having action_listen pushed could make it work (seems we need to have prev_action_listen before predicting anything new).
BUT this hack we do make us feel that we might struggle later into coming back to a previous conversation the manager was eventually having, as :
1- setting the state back could be possible,
2- but knowing WHEN the triggered intrusive conversation is really ending (to set back the tracker state at the right time) could be more difficult if it's longer than "can you validate => yes/no".
We have not yet been further so it's more like a philosophical questioning right now.

Conclusion : we managed to get around to make it work, but it was not that intuitive. Maybe all we did was crap, and if so you surely have some good advice to give us ^^


By the way, we REALLY appreciate the MultiProjectImporter. It's also just such a nice feature allowing real business logic segmentation ! :-)

@amn41
Copy link
Contributor

amn41 commented Oct 21, 2019

thanks for the super thoughtful write up!

@JEM-Mosig was proposing to change the notification functionality to look more like sending an intent, rather than triggering an action remotely. I suspect that will solve your problem.

Also I'd love to talk about your experiences with multiprojectimporter. Could you please shoot me an email? (firstname at company domain)

@JEM-Mosig
Copy link

JEM-Mosig commented Oct 21, 2019

The intent-trigger-issue is here: #4464

@darkblueorange
Copy link

Really nice, thanks to both of you. We're eager to have this intent-trigering feature now :-)
@amn41 , I've sent you a mail from "7lieues" domain :-)

@amn41
Copy link
Contributor

amn41 commented Oct 23, 2019

haven't seen your email, just fyi.

@mohocp
Copy link

mohocp commented Jan 5, 2020

Why it's not support sockotio channel ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:rasa-oss 🎡 Anything related to the open source Rasa framework type:enhancement ✨ Additions of new features or changes to existing ones, should be doable in a single PR
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants