# conversation
```go
import "github.com/lukaszraczylo/go-telegram/dispatch/conversation"
```
Package conversation implements a stateful conversation handler for the go\-telegram dispatch router. It provides a state\-machine abstraction over multi\-step Telegram bot interactions, with pluggable storage and flexible key strategies.
## Index
- [Variables](<#variables>)
- [func End\(\) error](<#End>)
- [func Next\(s State\) error](<#Next>)
- [type Conversation](<#Conversation>)
- [func \(c \*Conversation\) Dispatch\(next dispatch.Handler\[\*api.Update\]\) dispatch.Handler\[\*api.Update\]](<#Conversation.Dispatch>)
- [type Handler](<#Handler>)
- [type KeyStrategy](<#KeyStrategy>)
- [type MemoryStorage](<#MemoryStorage>)
- [func NewMemoryStorage\(\) \*MemoryStorage](<#NewMemoryStorage>)
- [func \(s \*MemoryStorage\) Delete\(\_ context.Context, key string\) error](<#MemoryStorage.Delete>)
- [func \(s \*MemoryStorage\) Get\(\_ context.Context, key string\) \(State, error\)](<#MemoryStorage.Get>)
- [func \(s \*MemoryStorage\) Set\(\_ context.Context, key string, state State\) error](<#MemoryStorage.Set>)
- [type State](<#State>)
- [type Step](<#Step>)
- [type Storage](<#Storage>)
## Variables
ErrKeyNotFound is returned by Storage.Get when no conversation is active for the given key.
```go
var ErrKeyNotFound = errors.New("conversation: key not found")
```
## func End
```go
func End() error
```
End signals the conversation has finished and state should be cleared. Conversation handlers return End\(\) to terminate.
## func Next
```go
func Next(s State) error
```
Next signals the conversation should advance to the given state. Conversation handlers return Next\("state\_name"\) to transition.
## type Conversation
Conversation is a stateful handler with entry, per\-state, exit and fallback steps. A conversation is keyed by KeyStrategy \(default KeyByUserAndChat\) and persisted by Storage \(default in\-memory\).
```go
type Conversation struct {
// EntryPoints starts a new conversation when a matching filter fires
// and no conversation is already active for the key.
EntryPoints []Step
// States maps each state to the steps that handle it.
States map[State][]Step
// Exits, if any match, end the active conversation early. Useful for
// /cancel-style commands.
Exits []Step
// Fallbacks run when no state step matches the current update.
Fallbacks []Step
// Storage persists conversation state. Defaults to NewMemoryStorage.
Storage Storage
// KeyStrategy derives the persistence key. Defaults to KeyByUserAndChat.
KeyStrategy KeyStrategy
// AllowReEntry, when true, lets entry-point steps fire even while a
// conversation is already active for the key (effectively restarting it).
AllowReEntry bool
}
```
### func \(\*Conversation\) Dispatch
```go
func (c *Conversation) Dispatch(next dispatch.Handler[*api.Update]) dispatch.Handler[*api.Update]
```
Dispatch is a global middleware\-shaped Handler that consumes updates and routes them through the conversation graph. Register via router.Use\(conv.Dispatch\).
If the conversation claims an update, downstream handlers are skipped. If the conversation does not claim it, downstream handlers run as normal.
## type Handler
Handler defines a step in the conversation. Receives the dispatch context and the raw update. Returns:
- nil to stay in the current state
- Next\("state"\) to transition to a different state
- End\(\) to end the conversation
- any other non\-nil error to surface to the dispatcher \(state unchanged\)
```go
type Handler func(ctx *dispatch.Context, u *api.Update) error
```
## type KeyStrategy
KeyStrategy derives a persistence key from an update. Strategies determine how conversation scope works — per\-user, per\-chat, or per\-user\-and\-chat. Implementations must return a stable string for the same logical scope across updates.
Returns the empty string if the update doesn't have enough context to derive a key \(in which case the conversation handler skips it\).
```go
type KeyStrategy func(u *api.Update) string
```
KeyByChat derives a key from the chat ID. Useful for group flows where any user in the chat can drive the conversation.
```go
var KeyByChat KeyStrategy = func(u *api.Update) string {
if cid := chatID(u); cid != 0 {
return fmt.Sprintf("c:%d", cid)
}
return ""
}
```
KeyByUser derives a key from the sending user's ID. Useful for DM conversations and any flow that should follow the user across chats.
```go
var KeyByUser KeyStrategy = func(u *api.Update) string {
if uid := userID(u); uid != 0 {
return fmt.Sprintf("u:%d", uid)
}
return ""
}
```
KeyByUserAndChat derives a key from both user and chat IDs. The most common strategy: each user has their own conversation per chat.
```go
var KeyByUserAndChat KeyStrategy = func(u *api.Update) string {
uid := userID(u)
cid := chatID(u)
if uid == 0 || cid == 0 {
return ""
}
return fmt.Sprintf("uc:%d:%d", cid, uid)
}
```
## type MemoryStorage
MemoryStorage is the default in\-process Storage. It is safe for concurrent use. Conversation state is lost on process restart; use a custom Storage backed by a database for persistent flows.
```go
type MemoryStorage struct {
// contains filtered or unexported fields
}
```
### func NewMemoryStorage
```go
func NewMemoryStorage() *MemoryStorage
```
NewMemoryStorage constructs an empty in\-memory storage.
### func \(\*MemoryStorage\) Delete
```go
func (s *MemoryStorage) Delete(_ context.Context, key string) error
```
### func \(\*MemoryStorage\) Get
```go
func (s *MemoryStorage) Get(_ context.Context, key string) (State, error)
```
### func \(\*MemoryStorage\) Set
```go
func (s *MemoryStorage) Set(_ context.Context, key string, state State) error
```
## type State
State is a label identifying a node in the conversation graph. The empty string is the implicit "no active conversation" state.
```go
type State string
```
## type Step
Step pairs a filter with a handler for one conversation step.
```go
type Step struct {
Filter dispatch.Filter[*api.Update]
Handler Handler
}
```
## type Storage
Storage persists per\-user \(or per\-chat, per\-message — depending on the KeyStrategy in use\) conversation state across update deliveries.
Implementations must be safe for concurrent use.
```go
type Storage interface {
Get(ctx context.Context, key string) (State, error)
Set(ctx context.Context, key string, state State) error
Delete(ctx context.Context, key string) error
}
```
Generated by [gomarkdoc]()