feat: `conversation.halt`
KnorpelSenf opened this issue ยท 13 comments
A lot of people ask for a way to exit conversations without returning or throwing. Similar to process.exit
, we should add conversation.halt
which stops the conversation immediately.
Calling ctx.conversation.exit
from within a conversation doesn't work well because the conversation continues to the next wait or skip, which is undesirable and not possible to avoid.
It should be called halt or terminate not exit in order to avoid confusion.
await conversation.halt(); // never resolves
So, if we do:
...
ctx = await conversation.waitFor(
<anything_but_text>,
(ctx) => ctx.message?.text === "/cancel" && conversation.halt()
);
...
What happens to this update? Does it get dropped? Or does it continue to be processed by the other middlewares (like in conversation.skip()
). Or should we do: conversation.halt().then(() => conversation.skip({ drop: true }))
like in #43
I would say that halt
should drop the update by default. But now that you say it, I do agree that there's a use case for halting the conversation, and giving back control to the middleware system. So perhaps we should rather do
ctx = await conversation.waitUnless(
Context.has.command("cancel"),
() => conversation.halt()
)
to end the conversation and handle it in the midleware system, and use
ctx = await conversation.waitUnless(
Context.has.command("cancel"),
() => conversation.halt({ drop: true })
)
to consume the update?
Yup! LGTM
Or maybe consuming the update should be the default, as you said; then you need to specify drop: false
to give back control to the middleware system?
That would be the same interface as for skip
but with a different default value. That would be pretty confusing, what do you think? ๐ค
Setting defaults to true
in these cases feels more natural to me, but I agree with you, they should be consistent between the two. I'm ok with either one, true for both, or false for both.
We cannot change the default value for skip
because that would be a breaking change. The current behaviour of skip (passing updates back the middleware system) is necessary to support parallel conversations, i.e. having several conversations in the same chat with different people.
But alright, then halt
will have to be implemented with false
as the default value, and permit to drop the most recent update using { drop: true }
.
Thanks for your input! ๐
Yo, I have been very busy with work. What's the status of this one? Is there something that needs to be tested/reviewed?
Not yet, it still remains to be implemented. Do you want to work on this?
hi, what if user leave the conversation by selecting any other commands int he middle of running a conversation? how to detect if any other command choose by user meanwhile?
You can install the command handlers before the respective conversation using bot.command
. If you don't call next
in them, the conversation won't be reached. See https://grammy.dev/guide/middleware
Adding https://t.me/grammyjs/235195 as a point of consideration.
Given potential use cases where one might try to call halt or exit inside the conversation function, but through a plugin; it raises some question on whether halt can naively explode.
Yep, calling halt from inside run should be supported