telega/bot
Core bot actor and chat instance management.
This module implements the actor-based architecture for handling Telegram updates.
It contains the Bot actor (the central dispatcher) and ChatInstance actors
(one per unique {chat_id}:{from_id} combination).
Supervision tree
Both the Bot actor and ChatInstance actors run inside a supervision tree
created by telega.init() or telega.init_for_polling():
TelegaRootSupervisor (static_supervisor, OneForOne)
├── ChatInstances (factory_supervisor, Transient children)
│ ├── ChatInstance {chat1:user1}
│ ├── ChatInstance {chat2:user2}
│ └── ...
├── Bot actor (worker, Permanent)
└── Polling worker (worker, Permanent) — only for polling mode
- The
Botactor is aPermanentworker — it always restarts on crash. ChatInstanceactors areTransient— they restart only on abnormal exit, not on normal shutdown. On restart aChatInstancere-registers itself in the ETS registry, overwriting the stale subject.- The
Botcreates newChatInstanceactors viafactory_supervisor.start_child, which ensures they are supervised from the moment they start.
Handler pattern
All handlers follow this signature:
fn handler(ctx: Context(session, error), data: Type) -> Result(Context(session, error), error)
Always return the updated context — it carries the (potentially modified) session.
Conversation API
The wait_handler function and the Handler type enable multi-message
conversations: the chat instance suspends its main handler and waits for a
specific update type. See telega.wait_text, telega.wait_command, etc.
Types
pub opaque type BotMessage
pub type BotSubject =
process.Subject(BotMessage)
pub type CallbackQueryFilter {
CallbackQueryFilter(re: regexp.Regexp)
}
Constructors
-
CallbackQueryFilter(re: regexp.Regexp)
Handler called when an error occurs in handler
If handler returns Error, the bot will be stopped and the error will be logged
The default handler is fn(_) -> Ok(Nil), which will do nothing if handler returns an error
pub type CatchHandler(session, error) =
fn(Context(session, error), error) -> Result(Nil, error)
Arguments for starting a chat instance via factory supervisor.
pub type ChatInstanceArgs(session, error) {
ChatInstanceArgs(
key: String,
config: @internal Config,
session_settings: SessionSettings(session, error),
catch_handler: fn(Context(session, error), error) -> Result(
Nil,
error,
),
router_handler: fn(Context(session, error), update.Update) -> Result(
Context(session, error),
error,
),
bot_info: types.User,
registry: @internal Registry(
ChatInstanceMessage(session, error),
),
)
}
Constructors
-
ChatInstanceArgs( key: String, config: @internal Config, session_settings: SessionSettings(session, error), catch_handler: fn(Context(session, error), error) -> Result( Nil, error, ), router_handler: fn(Context(session, error), update.Update) -> Result( Context(session, error), error, ), bot_info: types.User, registry: @internal Registry( ChatInstanceMessage(session, error), ), )
pub opaque type ChatInstanceMessage(session, error)
pub type ChatInstanceSubject(session, error) =
process.Subject(ChatInstanceMessage(session, error))
Context holds information needed for the bot instance and the current update.
pub type Context(session, error) {
Context(
key: String,
update: update.Update,
config: @internal Config,
session: session,
chat_subject: process.Subject(
ChatInstanceMessage(session, error),
),
start_time: option.Option(timestamp.Timestamp),
log_prefix: option.Option(String),
bot_info: types.User,
)
}
Constructors
-
Context( key: String, update: update.Update, config: @internal Config, session: session, chat_subject: process.Subject( ChatInstanceMessage(session, error), ), start_time: option.Option(timestamp.Timestamp), log_prefix: option.Option(String), bot_info: types.User, )Arguments
- start_time
-
Used to calculate the duration of the conversation in logs
pub type Handler(session, error) {
HandleAll(
handler: fn(Context(session, error), update.Update) -> Result(
Context(session, error),
error,
),
)
HandleCommand(
command: String,
handler: fn(Context(session, error), update.Command) -> Result(
Context(session, error),
error,
),
)
HandleCommands(
commands: List(String),
handler: fn(Context(session, error), update.Command) -> Result(
Context(session, error),
error,
),
)
HandleText(
handler: fn(Context(session, error), String) -> Result(
Context(session, error),
error,
),
)
HandleHears(
hears: Hears,
handler: fn(Context(session, error), String) -> Result(
Context(session, error),
error,
),
)
HandleMessage(
handler: fn(Context(session, error), types.Message) -> Result(
Context(session, error),
error,
),
)
HandleVoice(
handler: fn(Context(session, error), types.Voice) -> Result(
Context(session, error),
error,
),
)
HandleAudio(
handler: fn(Context(session, error), types.Audio) -> Result(
Context(session, error),
error,
),
)
HandleVideo(
handler: fn(Context(session, error), types.Video) -> Result(
Context(session, error),
error,
),
)
HandlePhotos(
handler: fn(Context(session, error), List(types.PhotoSize)) -> Result(
Context(session, error),
error,
),
)
HandleWebAppData(
handler: fn(Context(session, error), types.WebAppData) -> Result(
Context(session, error),
error,
),
)
HandleCallbackQuery(
filter: CallbackQueryFilter,
handler: fn(Context(session, error), String, String) -> Result(
Context(session, error),
error,
),
)
HandleChatMember(
handler: fn(Context(session, error), types.ChatMemberUpdated) -> Result(
Context(session, error),
error,
),
)
}
Constructors
-
HandleAll( handler: fn(Context(session, error), update.Update) -> Result( Context(session, error), error, ), )Handle all messages.
-
HandleCommand( command: String, handler: fn(Context(session, error), update.Command) -> Result( Context(session, error), error, ), )Handle a specific command.
-
HandleCommands( commands: List(String), handler: fn(Context(session, error), update.Command) -> Result( Context(session, error), error, ), )Handle multiple commands.
-
HandleText( handler: fn(Context(session, error), String) -> Result( Context(session, error), error, ), )Handle text messages.
-
HandleHears( hears: Hears, handler: fn(Context(session, error), String) -> Result( Context(session, error), error, ), )Handle text message with a specific substring.
-
HandleMessage( handler: fn(Context(session, error), types.Message) -> Result( Context(session, error), error, ), )Handle any message.
-
HandleVoice( handler: fn(Context(session, error), types.Voice) -> Result( Context(session, error), error, ), )Handle voice messages.
-
HandleAudio( handler: fn(Context(session, error), types.Audio) -> Result( Context(session, error), error, ), )Handle audio messages.
-
HandleVideo( handler: fn(Context(session, error), types.Video) -> Result( Context(session, error), error, ), )Handle video messages.
-
HandlePhotos( handler: fn(Context(session, error), List(types.PhotoSize)) -> Result( Context(session, error), error, ), )Handle photo messages.
-
HandleWebAppData( handler: fn(Context(session, error), types.WebAppData) -> Result( Context(session, error), error, ), )Handle web app data messages.
-
HandleCallbackQuery( filter: CallbackQueryFilter, handler: fn(Context(session, error), String, String) -> Result( Context(session, error), error, ), )Handle callback query. Context, data from callback query and
callback_query_idare passed to the handler. -
HandleChatMember( handler: fn(Context(session, error), types.ChatMemberUpdated) -> Result( Context(session, error), error, ), )Handle chat member update (when user joins/leaves a group). The bot must be an administrator in the chat and must explicitly specify “chat_member” in the list of
allowed_updatesto receive these updates.
pub type Hears {
HearText(text: String)
HearTexts(texts: List(String))
HearRegex(regex: regexp.Regexp)
HearRegexes(regexes: List(regexp.Regexp))
}
Constructors
-
HearText(text: String) -
HearTexts(texts: List(String)) -
HearRegex(regex: regexp.Regexp) -
HearRegexes(regexes: List(regexp.Regexp))
pub type SessionSettings(session, error) {
SessionSettings(
persist_session: fn(String, session) -> Result(session, error),
get_session: fn(String) -> Result(
option.Option(session),
error,
),
default_session: fn() -> session,
)
}
Constructors
-
SessionSettings( persist_session: fn(String, session) -> Result(session, error), get_session: fn(String) -> Result(option.Option(session), error), default_session: fn() -> session, )
Values
pub fn cancel_conversation(
bot bot: Bot(session, error),
key key: String,
) -> Nil
Stops waiting for any handler for specific key (chat_id)
pub fn get_session(
session_settings: SessionSettings(session, error),
update: update.Update,
) -> Result(option.Option(session), error)
pub fn next_session(
ctx ctx: Context(session, error),
session session: session,
) -> Result(Context(session, error), error)
pub fn start(
registry registry: @internal Registry(
ChatInstanceMessage(session, error),
),
config config: @internal Config,
bot_info bot_info: types.User,
router_handler router_handler: fn(
Context(session, error),
update.Update,
) -> Result(Context(session, error), error),
session_settings session_settings: SessionSettings(
session,
error,
),
catch_handler catch_handler: fn(Context(session, error), error) -> Result(
Nil,
error,
),
chat_factory chat_factory: factory_supervisor.Supervisor(
ChatInstanceArgs(session, error),
process.Subject(ChatInstanceMessage(session, error)),
),
name name: option.Option(process.Name(BotMessage)),
) -> Result(
actor.Started(process.Subject(BotMessage)),
actor.StartError,
)
pub fn start_chat_instance(
args: ChatInstanceArgs(session, error),
) -> Result(
actor.Started(
process.Subject(ChatInstanceMessage(session, error)),
),
actor.StartError,
)
Start a chat instance. Used as the template function for factory_supervisor. Self-registers in the registry on start (handles both first start and restart after crash).
pub fn wait_handler(
ctx ctx: Context(session, error),
handler handler: Handler(session, error),
handle_else handle_else: option.Option(Handler(session, error)),
timeout timeout: option.Option(Int),
) -> Result(Context(session, error), error)
Pass any handler to start waiting
or - calls if there are any other updates
timeout - the conversation will be canceled after this timeout