| name | build-wizard-flow |
| description | [Bot developer] Creates multi-step wizard flows with validation and state persistence using @WizardHandler and WizardStep. Use when building forms, questionnaires, or multi-step conversations that need typed state and validation. |
Build Wizard Flow
Quick Start
Annotate an object/class with @WizardHandler. Define nested steps extending WizardStep. KSP generates the WizardActivity; no manual Activity class needed.
import eu.vendeli.tgbot.types.component.MessageUpdate
@WizardHandler(trigger = ["/start"])
object RegistrationWizard {
object NameStep : WizardStep(isInitial = true) {
override suspend fun onEntry(ctx: WizardContext) {
message("What's your name?").send(ctx.user, ctx.bot)
}
override suspend fun validate(ctx: WizardContext): Transition {
val text = (ctx.update as? MessageUpdate)?.message?.text ?: return Transition.Retry()
return if (text.isNotBlank()) Transition.Next else Transition.Retry("Invalid name")
}
override suspend fun store(ctx: WizardContext): String? =
(ctx.update as? MessageUpdate)?.message?.text
}
object AgeStep : WizardStep() {
override suspend fun onEntry(ctx: WizardContext) {
message("How old are you?").send(ctx.user, ctx.bot)
}
override suspend fun validate(ctx: WizardContext): Transition {
val age = (ctx.update as? MessageUpdate)?.message?.text?.toIntOrNull()
return if (age != null && age in 1..150) Transition.Next else Transition.Retry()
}
override suspend fun store(ctx: WizardContext): Int? =
(ctx.update as? MessageUpdate)?.message?.text?.toIntOrNull()
}
}
WizardStep Lifecycle
- onEntry(ctx) — Called when entering the step. Send prompts, set keyboards.
- validate(ctx) — Return
Transition based on input.
- store(ctx) — Return value to persist (or null). Type must match a state manager.
- onRetry(ctx, reason) — Called when validation fails (optional).
Transitions
| Transition | Effect |
|---|
Transition.Next | Move to next step in sequence |
Transition.JumpTo(Step::class) | Jump to specific step |
Transition.Retry() or Transition.Retry("reason") | Stay on step, call onRetry |
Transition.Finish | End wizard |
State Managers
Default: MapStringStateManager, MapIntStateManager, MapLongStateManager. KSP matches store() return type to the manager.
Override per step:
@WizardHandler.StateManager(CustomStateManager::class)
object CustomStep : WizardStep { ... }
WizardContext
ctx.user, ctx.update, ctx.bot
ctx.getState(Step::class), ctx.setState(Step::class, value), ctx.delState(Step::class) — type-safe accessors generated by KSP for each step
Trigger and Scope
trigger = ["/start", "/register"] — commands that start the wizard
scope = [UpdateType.MESSAGE] — default; use UpdateType.CALLBACK_QUERY for button-triggered wizards
Related Skills
- add-wizard-handler — Configure @WizardHandler (trigger, scope, state managers)
- add-wizard-step — Implement WizardStep (onEntry, validate, store, transitions)
Reference