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

Persistent menu action during a conversation #24

Open
MrLepage opened this issue Feb 15, 2017 · 20 comments
Open

Persistent menu action during a conversation #24

MrLepage opened this issue Feb 15, 2017 · 20 comments
Labels

Comments

@MrLepage
Copy link

Hi,

From what I understand, bot.on and bot.hear are bypassed during a conversation.
Since callback from persistent menu are handled in bot.hear, how can we handle those events during a conversation ?

@Charca
Copy link
Owner

Charca commented Feb 17, 2017

Hey @uncvr,

Thanks for bringing this up, this is an interesting scenario. You're correct, persistent menu callbacks are bypassed during a conversation, so we definitely need to find a solution for this.

I'm thinking we could identify which postbacks belong to a persistent menu button and make sure we execute their callbacks even if we're in the middle of a conversation. The only problem that I see with this is that if one of these callbacks starts a new conversation, the bot would lose track of the previous one. The concept of sub-conversations is something I thought about when designing the first version, and it would definitely come in handy here, but I think is out of the scope of this particular problem.

I'll start working on a solution that fixes the persistent menu issue without interrupting the flow of the original conversation, we can then handle the sub-conversation issue separately. Thoughts?

@Charca Charca added the bug label Feb 17, 2017
@mraaroncruz
Copy link
Collaborator

I think you need to work out some use cases here, real scenarios.
I feel like if you started a second conversation, that in most cases that I can think of, it would be fine to drop the first conversation on the floor.

But it depends on how you're handling your conversations. If you're handling then from "What does this user look like in the database?" then dropping the original convo would be fine. If it's more like the convo API is set up, holding state in some kind of a linked list in memory, then if the original convo's state is important, we're in trouble.

So unless you completely re-design how conversations are implemented, this is really a case by case issue. Maybe the solution would be to add more introspection or control into how conversations are handled, to give people who need more control to have that control.

What makes the most sense to me is:

  • user is in a conversation
  • user clicks on menu item
  • convo put on hold and help is handled
    • if user responds to original convo
      • user returned to paused convo
    • starts new convo
      • new convo replaces old one

What's the worst possible situation in each scenario?
(sorry for the brain dump :) )

@sotirelisc
Copy link

Any updates on when this might be implemented? As the bot grows, the need to "hear" persistent menu postbacks when in any conversation, increases. :D

@Charca
Copy link
Owner

Charca commented Apr 4, 2017

Alright, I've been thinking about this and I think I have a pretty solid idea of what we should do in this case. As @pferdefleisch mentioned, we should think about real use cases where this might become a problem for the two possible scenarios (always considering that the user was in the middle of a conversation and at some point, clicked on a menu item):

  1. Menu item starts a new conversation.
  2. Menu item just sends a message (for example a Help menu).

For 1) I think it's pretty clear that we need to drop the original conversation and start the new one. Worst case scenario here is that the bot was saving information in the conversation's context (using convo.set()) and by ending the conversation they'll lose access to this information. If this is the case, hooking up to the 'end' event of the conversation should allow them to save the information before the conversation is replaced by the new one. Do you think this would be enough or do you see any other issues that this could cause?

For 2), I'm not entirely sure that we should keep the conversation alive because it might be confusing from the user's perspective. Consider the following example:

> Bot: "What's your name?"
< User: "Maxi"
> Bot: "Hi, Maxi! Where do you live?"
* User clicks on Help Menu item *
> Bot: "Here are the Help options, you can type: SETTINGS, ABOUT, STOP or HELP."
-----
Now, at this point if we didn't end the conversation (because the menu item
didn't start a new one), the bot is still waiting for the answer to the
"Where do you live?" question, but from the user's perspective this is not very clear.
It looks like the flow was interrupted and they might try to talk about something else: 
-----
< User: "SETTINGS"
> Bot: "Oh, you live in SETTINGS, nice! I hope it's sunny over there!"
< User: "#botfail"

So for scenarios like this one, I'm leaning towards ending the conversation even if the menu item didn't start a new one.

I'd love your thoughts on this one before I start working on it.

@sotirelisc
Copy link

I agree that it should end the current conversation but it should be designed to listen to specific persistent menu items. I was thinking an item like "Cancel Conversation" that would help the user cancel at anytime.

@Charca
Copy link
Owner

Charca commented Apr 4, 2017

@sotirelisc do you mean manually ending the conversation with a "Cancel Conversation" item in the Persistent Menu? I was thinking that ANY persistent menu item should end the current conversation before doing whatever it is the menu item does.

Also, the persistent menu is a single instance that is shared across all users, so you won't be able to update it depending on whether the user is in a conversation or not. If you wanted to have a "Cancel Conversation" button in the Persistent Menu that is visible only when the user is in the middle of a conversation, I'm afraid it's not possible at the moment due to the way Facebook handles this menu.

@sotirelisc
Copy link

@Charca, I was thinking that the "Cancel Conversation" item will be always there but it would function only if there is an active conversation.
Making every item ending a conversation seems dangerous to me, as a user could accidentally press it.

@mraaroncruz
Copy link
Collaborator

This is a UX issue. A user doesn't know they are in a "Conversation". They are just chatting with a bot.

@sotirelisc
Copy link

@pferdefleisch, yes, but they probably know they are inside an ordering process. They know that they have started something that sometime in the future will end.

@sotirelisc
Copy link

@Charca, any ideas on this one?

@mraaroncruz
Copy link
Collaborator

IMO, a menu button push should end any current conversation.
This means: If you are building an app with conversations and a menu, you would have to hold more state in your data store and handle where your conversation is when new conversations are started.

This seems like a fair tradeoff to me because I believe this issue really is a bug.

A practical example:

user: Hi
bot: Hi Human! What is your name?
user: I'm Charca!
bot: Oh, hi Charca! How old are you?
user: MENU => Help
# This just removed current conversation from brain
bot: You can: <contact me> <add a task> <cancel reminders>
user: <cancel reminders>
bot: reminders cancelled.
user: hi
# at this point you check that you already have the user's name
bot: hi Charca, I still need you age. How old are you?
user: ...

Cheers

@sotirelisc
Copy link

In my case, I'm building an ordering bot. I can't have users canceling a whole order just because they hit an item of the persistent menu. However, if for any reason the bot becomes unresponsive during the ordering proccess, a canceling option in the persistent menu, would be great.

@mraaroncruz
Copy link
Collaborator

I imagine you would keep your order state somewhere so you wouldn't have to drop your order on the floor. You would just need to do something like check if there is an open order after each menu or other out of bound response and give the user an option to continue the order:

user: Hi
bot: Hi Human! What do you want from the web shopppp?
user: Cheetos!
bot: Cheetos? Well, ok. How many packages?
user: MENU => Help
# This just removed current conversation from brain
bot: You can: <contact me> <add a task> <cancel reminders>
user: <cancel reminders>
bot: reminders cancelled.
bot: what would you like to do now <continue order> <search for more products> <eat cheetos all day>
user: <continue order>
# at this point you check that you already have the user's item
bot: Great. How many packages of cheetos did you want?
user: 1000000
...

@mraaroncruz
Copy link
Collaborator

I think this is a fair tradeoff, allows flexibility and won't add a bunch of complexity to the codebase. It probably only needs a "Is this a menu (out of bound) postback? Ok: Deal with it. No: Are we in a conversation? Yes: handle conversation. No: Send to hear's...
One added check.

@sotirelisc
Copy link

@pferdefleisch, hmm.. Yes, sounds like a legit solution.

@michaelreda
Copy link

any suggestions/modifications on how to break the old conversation out (and not completing it) and start a new one when a menu button is clicked ? @Charca

@giacomocerquone
Copy link

giacomocerquone commented May 1, 2017

And here is why my bot was acting very strange. I was experiencing this problem with my bot.
I'm going to explain my scenario:
I have this bot and I want users to write tv shows to him in order to return some information about these shows. The point is that if I write and send a tv shows and it returns the information, then if I hit a menu button (that could be, "help" or "trending tv shows") it won't work most of the times (and I still have to figure out why sometimes it works)

@temrysh
Copy link

temrysh commented May 28, 2017

@michaelreda
Try to catch actions in callbacks and do your stuff there.
Alike:

const callbacks = [{
  event: 'postback:START',
  callback: (payload, convo, data) => {
    convo.end();
    bot._handleEvent('postback:START', payload, data);
  }
}];

or use conversation(recipientId, factory)

@mraaroncruz
Copy link
Collaborator

This solution is a hack (calling a "private" method) which works currently but relies on private implementation details that could change at any time.

There is a place to hook into this, and the framework already does it for postback buttons that are created with a string. The framework sets "BOOTBOT_"+buttonName.toUpperCase() on these buttons postbacks.
This same functionality could be hooked into in the setPersistentMenu() method and the _handleMessageEvent(event) could listen for menu events by matching maybe BOOTBOT_MENU_ to the postback and then skip the conversation or delete the conversation instead of handling the conversation right away.
My other pull requests aren't being looked at so I will wait to do this until I need it (which will likely be very soon).

Does this sound reasonable to everyone?

@jhenriquez
Copy link

Hey! It seems I've got a little late to the conversation :)

First, I upvoted some of the comments above because I agree a current conversation can be dropped if the user calls a persistent menu postback, specially if I would be able to subscribe to the end event and have access to the last shared state of the convo as @Charca pointed out in the beginning.

My scenario is similar but not quite the "Cancel button", because I want to react in such a way that if the user wants to start over I drop the data I have and restart my conversation from the first interaction, there my first interaction can maybe look for my persistent state 🤔 and take it from there.

But I got a little lost in the the last two comments, I'm not sure I follow @tmwd 's hack, or understand what @mraaroncruz is suggesting. In short, is there a way for me to hook up into the post backs that are being dropped by the conversation or not?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants