Skip to main content
Agents can reply with structured interactive messages — buttons, dropdowns, dividers, context text — and each channel adapter renders them as native widgets.

Quick Start

1

Reply with two buttons

from praisonaiagents import Agent
from praisonaiagents.bots import (
    MessagePresentation,
    PresentationBlock,
    PresentationButton,
    PresentationAction,
)

def confirm_action(_args=None) -> MessagePresentation:
    return MessagePresentation(blocks=[
        PresentationBlock.make_text("Ready to deploy?"),
        PresentationBlock.make_buttons([
            PresentationButton(
                label="Deploy",
                action=PresentationAction(type="command", command="/deploy confirm"),
                style="primary",
            ),
            PresentationButton(
                label="Cancel",
                action=PresentationAction(type="command", command="/deploy cancel"),
                style="danger",
            ),
        ]),
    ])

agent = Agent(name="DeployBot", instructions="Confirm before deploying", tools=[confirm_action])
agent.start("Deploy main to production")
2

Dropdown selection

from praisonaiagents.bots import (
    MessagePresentation,
    PresentationBlock,
    SelectOption,
)

presentation = MessagePresentation(blocks=[
    PresentationBlock.make_text("Pick an environment:"),
    PresentationBlock.make_select(
        options=[
            SelectOption(label="Staging", value="staging", emoji="🧪"),
            SelectOption(label="Production", value="prod", emoji="🚀", default=True),
        ],
        placeholder="Choose an environment",
        action_id="env_select",
    ),
])
3

One-line approval prompt

from praisonaiagents.bots import MessagePresentation

presentation = MessagePresentation.approval(
    prompt="Allow delete_file for /var/log/old.log?",
    approval_id="appr_abc123",
    allow_always=True,
    context="Tool requested by agent: ops-bot",
)

How It Works

ChannelNative renderingFallback
TelegramInline keyboardPlain text
SlackBlock KitPlain text
DiscordComponentsPlain text
WhatsAppPlain text only

Block Types

BlockFactoryUse for
Textmake_text(content)Markdown body
Buttonsmake_buttons(items)Action rows
Selectmake_select(options)Dropdown menus
Dividermake_divider()Visual separator
Contextmake_context(content)Smaller hint text
Higher priority on PresentationButton survives when renderers trim to channel limits.

Approval Prompts

On channels implementing SupportsPresentation, approval prompts render as inline Allow Once, Allow Always, and Deny buttons wired to /approve <approval_id> ... commands — replacing fragile yes/no text classification. Text-keyword backends (TelegramApproval, SlackApproval, DiscordApproval) remain valid fallbacks for channels without presentation support.

Best Practices

PresentationBlock.make_text() and make_buttons() are the agent-friendly path — fewer field mistakes than raw dataclass construction.
Give Deny or Cancel higher priority so they survive truncation on Discord’s stricter component limits.
Always set MessagePresentation text content so WhatsApp and email channels still deliver a readable message.
The built-in helper wires standard Allow/Deny buttons consistently across Telegram, Slack, and Discord.

Approval Protocol

Tool approval backends

Bot Gateway

Multi-channel gateway server