Quick Start
1
Author a poll
An agent returns a
MessagePresentation with a POLL block — one question and two or more options:2
Receive the tally
Register a poll-result handler under
POLL_NAMESPACE so the aggregated vote comes back as a typed PollResult:How It Works
A POLL block stays native on channels that advertisesupports_native_poll=True; everywhere else it degrades to a question TEXT block plus a reply-button per option.
All poll options
PresentationBlock.make_poll(question, options, *, multiple_choice=False, anonymous=True, duration_seconds=None, action_id=None) sets these fields on the block:
The
question is stored on text, and action_id correlates the inbound result.
Degradation reporting
On a channel with no native poll,adapt_presentation_with_report turns the POLL into a question TEXT block plus a reply-buttons grid, and records the loss:
DEGRADE_POLL_AS_BUTTONS = "poll_rendered_as_buttons" imports from praisonaiagents.bots, and report.dropped reads "poll (3 options) rendered as buttons". See Degraded Delivery.
PollResult
The aggregated tally comes back as a typedPollResult, portable across channels:
winner() returns the top option, or None on a tie or an empty poll — it never silently picks:
to_dict() / from_dict() round-trip a result losslessly: PollResult.from_dict(result.to_dict()) == result.
Which option should I choose?
Best Practices
Set action_id so PollResult.poll_id maps back to the poll
Set action_id so PollResult.poll_id maps back to the poll
Pass
action_id="slot" to make_poll and the inbound PollResult.poll_id carries the same value — so a workflow knows which poll a tally belongs to.Handle ties explicitly — winner() returns None
Handle ties explicitly — winner() returns None
winner() returns None on a tie or empty poll rather than picking arbitrarily. Branch on None and decide the tie-break yourself.Assume degradation on Telegram/Slack/Discord today
Assume degradation on Telegram/Slack/Discord today
PresentationLimits.telegram(), .slack(), and .discord() all set supports_native_poll=False today, so polls render as a question plus reply-buttons. Opt in via a custom PresentationLimits(supports_native_poll=True) once a renderer ships a native-poll branch.Keep option labels short and unique
Keep option labels short and unique
After degradation each label doubles as a button caption and as the
reply payload string, so short, distinct labels stay within the callback byte-cap and never collide.Related
Bot Presentations
Buttons, selects, tables, charts, and polls across channels
Message Presentation
Attach blocks to agent replies
Degraded Delivery
See what a channel could not render natively
Interactive Bot Actions
Route inbound clicks and poll results to handlers

