Collectors are a small convenience layer over OnMessageCreate. They observe
matching events without preventing other message handlers from running.
Wait for one message
Use AwaitMessage for forms, confirmations, and other one-response flows:
event, err := client.AwaitMessage(ctx, osmose.MessageCollectorOptions{
Chat: chat,
AuthorID: userID,
Time: 60 * time.Second,
Filter: func(event *osmose.MessageCreateEvent) bool {
return event.Message.Content != ""
},
})
if err != nil {
return err
}
return event.Reply(ctx, "Recebi: "+event.Message.Content)
AwaitMessage automatically stops after the first matching message.
Collect several messages
collector, err := client.CollectMessages(osmose.MessageCollectorOptions{
Chat: chat,
Time: 2 * time.Minute,
Idle: 30 * time.Second,
Max: 5,
Buffer: 16,
})
if err != nil {
return err
}
defer collector.Stop(osmose.EndReasonStopped)
for event := range collector.Events() {
log.Println(event.Message.Content)
}
result := collector.Result()
log.Println(result.Collected, result.Reason)
Events() is closed when the collector ends. Done() can be used when the
consumer does not need to range over events. Next(ctx) waits for one event
and respects a separate context. Use CollectMessagesContext(ctx, options)
when a multi-message collector belongs to a request or interaction lifetime.
Interaction collectors
Use AwaitInteraction for buttons or other interaction data emitted by the
current Osmium protocol:
interaction, err := client.AwaitInteraction(ctx, osmose.InteractionCollectorOptions{
UserID: userID,
MessageID: messageID,
Data: "confirm",
Time: time.Minute,
})
if err != nil {
return err
}
return interaction.Reply(ctx, "Confirmed")
For multiple interactions, use CollectInteractions or
CollectInteractionsContext. The collector exposes the same Events,
Next, Done, Result, and Stop methods as a message collector.
CollectReactions and AwaitReaction are available for the protocol's
message-reaction snapshots. Filter them with Chat, MessageID, and a typed
Filter; the returned MessageReactionsEvent includes the message ID and the
current reaction state.
Filters and limits
| Option | Behavior |
|---|---|
Chat |
Accept messages from one chat; the zero value accepts any chat. |
AuthorID |
Accept messages from one author; zero accepts any author. |
Filter |
Apply an additional typed predicate. |
Time |
Stop after the total duration. |
Idle |
Stop after no matching message for the duration. |
Max |
Stop after this many matching messages; zero is unlimited. |
Buffer |
Maximum queued matches; zero uses the default buffer. |
InteractionCollectorOptions uses UserID, MessageID, Data, and a typed
Filter in place of the message Chat and AuthorID fields. Its lifetime and
buffer options are the same.
ReactionCollectorOptions uses Chat, MessageID, Filter, Time, Idle,
Max, and Buffer.
The buffer is bounded. If it fills, the collector ends with
ErrCollectorOverflow instead of blocking the event dispatcher indefinitely.
Keep filters fast because they run in the existing bounded event worker pool.
Form example
A form can be composed from AwaitMessage calls:
func ask(ctx context.Context, client *osmose.Client, chat types.ChatRef, userID types.ID, prompt string) (string, error) {
if _, err := client.Messages.Send(ctx, messages.SendParams{
Chat: chat,
Content: prompt,
}); err != nil {
return "", err
}
event, err := client.AwaitMessage(ctx, osmose.MessageCollectorOptions{
Chat: chat,
AuthorID: userID,
Time: 2 * time.Minute,
})
if err != nil {
return "", err
}
return event.Message.Content, nil
}
Collectors also stop automatically when the client closes. Use a context with
AwaitMessage for request-scoped flows; a client shutdown is reported as
ErrCollectorClosed. Add validation, retries, and application-specific state
around these helpers when a form needs them.
End reasons
CollectorResult.Reason is one of EndReasonTime, EndReasonIdle,
EndReasonLimit, EndReasonStopped, EndReasonContext, or
EndReasonOverflow, or EndReasonClosed. Timeout, idle, overflow, and client
shutdown results expose typed errors for errors.Is checks.