DSL and behaviour for building multi-step conversation flows.
A flow is a module that declares a sequence of steps. Each step has a prompt
(sent to the user) and the module implements handle_input/3 to process
responses and control transitions.
Example
defmodule MyBot.Flows.Registration do
use Hotline.Flow
step :name, prompt: "What's your name?"
step :email, prompt: fn ctx -> "Thanks #{ctx.data.name}! What's your email?" end
step :confirm,
prompt: fn ctx ->
"Confirm?\nName: #{ctx.data.name}\nEmail: #{ctx.data[:email] || "skipped"}"
end,
keyboard: [[%{text: "Yes", callback_data: "yes"}, %{text: "No", callback_data: "no"}]]
@impl true
def handle_input(:name, %{message: %{text: name}}, _ctx) when byte_size(name) >= 2 do
{:next, store: %{name: name}}
end
def handle_input(:name, _, _ctx), do: {:retry, "Name must be at least 2 characters."}
def handle_input(:email, %{message: %{text: "/skip"}}, _ctx), do: {:next, store: %{email: nil}}
def handle_input(:email, %{message: %{text: email}}, _ctx) do
if String.contains?(email, "@"),
do: {:next, store: %{email: email}},
else: {:retry, "Invalid email. Try again or /skip."}
end
def handle_input(:confirm, %{callback_query: %{data: "yes"}}, _ctx), do: :done
def handle_input(:confirm, %{callback_query: %{data: "no"}}, _ctx), do: {:goto, :name, reset: true}
def handle_input(:confirm, _, _ctx), do: {:retry, "Use the buttons above."}
endReturn Values
handle_input/3 must return one of:
:next— advance to the next step in sequence{:next, store: %{key: value}}— merge data, then advance{:goto, step}— jump to a named step{:goto, step, reset: true}— jump and clear accumulated data{:retry, message}— stay on the current step, send error message:done— complete the flow{:done, result}— complete with a result value:cancel— cancel the flow
Optional Callbacks
on_done/1— called when the flow completes (receives the final context)on_cancel/1— called when the flow is cancelled
Running Flows
Use Hotline.Flow.Engine to manage active flows. See Hotline.Flow.Runner
for the pure execution logic.
Summary
Functions
Declare a step in the flow.
Types
Callbacks
@callback handle_input(step :: atom(), update :: map(), ctx :: Hotline.Flow.Context.t()) :: step_result()
@callback on_cancel(ctx :: Hotline.Flow.Context.t()) :: any()
@callback on_done(ctx :: Hotline.Flow.Context.t()) :: any()