Skip to main content
from praisonaiagents import Agent

agent = Agent(name="assistant", instructions="Answer helpfully on chat platforms.")
agent.start("What is the status of order #42?")
DisplayPolicy lets operators control how agent output is presented on each channel — streaming partial answers, showing tool progress, or sending a single final message — without touching adapter code. The user messages the bot on a channel; display policy controls streaming, tool progress, and final message shape per platform.

How It Works

Resolution Precedence

Quick Start

1

Use Platform Defaults (No Config)

Zero configuration: Telegram streams replies live, Slack posts discrete steps, Email sends one final message. Platform-tier defaults do the right thing automatically:
from praisonaiagents import Agent
from praisonai.bots import TelegramBot

agent = Agent(
    name="Assistant",
    instructions="Answer questions helpfully.",
)

bot = TelegramBot(token="YOUR_TOKEN", agent=agent)
await bot.start()
2

Override One Field Globally

Turn off streaming for all platforms:
from praisonaiagents import Agent, DisplayPolicy
from praisonai.bots import TelegramBot, BotConfig

config = BotConfig(
    display={"streaming": "off"}
)

agent = Agent(name="Assistant", instructions="Answer questions.")
bot = TelegramBot(token="YOUR_TOKEN", agent=agent, config=config)
await bot.start()
3

Override Per Platform

Enable a compact footer on Telegram only:
from praisonai.bots import BotConfig

config = BotConfig(
    display={
        "platforms": {
            "telegram": {"footer": "compact"},
            "email": {"streaming": "off"},
        }
    }
)
Platform keys are case-insensitive"Telegram", "TELEGRAM", and "telegram" all match.
4

Use the DisplayPolicy Dataclass

from praisonaiagents import DisplayPolicy
from praisonaiagents.bots import resolve_display_policy

policy = resolve_display_policy(
    "telegram",
    {"streaming": "draft", "platforms": {"telegram": {"footer": "compact"}}}
)

print(policy.streaming)        # "draft"
print(policy.footer)           # "compact"
print(policy.tool_progress)    # "off"

How It Works

The resolver applies this priority order for every field independently:
  1. Platform overridedisplay.platforms.<platform> (matched case-insensitively, so {Telegram: ...} works for "telegram")
  2. Global field — the top-level DisplayPolicy field
  3. Platform-tier default — automatic default based on the channel’s tier (edit, work, noedit, batch)
  4. Built-in default — the hard-coded fallback

Configuration Options

FieldTypeDefaultDescription
streaming"off" | "draft" | "progress""off"How to stream partial replies: off, show draft updates, or show progress markers
tool_progress"off" | "inline""off"Whether to print tool-call progress inline during execution
interim_assistant_messagesboolFalseWhether to send “thinking…” messages between tool calls
footer"off" | "compact""off"Append a compact attribution/source footer to replies
platformsdict[str, DisplayPolicy]{}Per-platform overrides; keys are matched case-insensitively

Platform Tiers

TierPlatformsDefault Behaviour
editTelegram, Discordstreaming="draft" — edits the message as content arrives
workSlack, Lineartool_progress="inline" — shows tool steps without streaming
noeditEmail, SMS, AgentMailstreaming="off" — waits for completion, sends one message
batchBulk broadcaststreaming="off", interim_assistant_messages=False
String booleans ("false", "0") are parsed correctly in YAML/JSON config files, so interim_assistant_messages: "false" works as expected.

Common Patterns

Telegram with draft streaming

from praisonaiagents import Agent
from praisonaiagents.bots import DisplayPolicy

agent = Agent(
    name="assistant",
    instructions="Be helpful",
    display=DisplayPolicy(streaming="draft", interim_assistant_messages=True),
)
from praisonaiagents.bots import DisplayPolicy

display = DisplayPolicy(streaming="off", footer="compact")

Different settings per channel

from praisonaiagents.bots import DisplayPolicy

display = DisplayPolicy(
    streaming="off",          # global default: no streaming
    platforms={
        "telegram": DisplayPolicy(streaming="draft"),
        "discord":  DisplayPolicy(streaming="draft"),
        "slack":    DisplayPolicy(tool_progress="inline"),
    },
)

## Configuration Options

All four fields are set via the `display:` block in your bot config:

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `streaming` | `"off" \| "draft" \| "progress"` | `"off"` | When to surface partial assistant output: `"off"` (single final message), `"draft"` (edit in place), `"progress"` (compact status then final) |
| `tool_progress` | `"off" \| "inline"` | `"off"` | Whether to show tool-call progress markers: `"off"` (hidden) or `"inline"` (progress bubbles) |
| `interim_assistant_messages` | `bool` | `False` | Whether to send intermediate assistant messages before the final reply |
| `footer` | `"off" \| "compact"` | `"off"` | Runtime footer appended to replies: `"off"` or `"compact"` (e.g. `model · ctx% · cwd`) |

<Note>
`interim_assistant_messages` accepts string booleans from YAML/JSON/env: `"true"`, `"1"`, `"yes"`, `"on"``True`; `"false"`, `"0"`, `"no"`, `"off"``False`. Using `"off"` as a string evaluates to `False` (not `True`).
</Note>

---

## Platform Tiers and Built-in Defaults

Each platform maps to a tier that controls sensible defaults:

| Tier | Platforms | `streaming` | `tool_progress` | `footer` |
|------|-----------|-------------|----------------|---------|
| `edit` | Telegram, Discord | `"draft"` | `"off"` | `"off"` |
| `work` | Slack, Teams, Mattermost | `"off"` | `"inline"` | `"off"` |
| `noedit` | WhatsApp | `"off"` | `"off"` | `"off"` |
| `batch` | Email, SMS | `"off"` | `"off"` | `"off"` |

Platforms not listed above resolve to the built-in default (`streaming="off"`, all others `"off"` / `False`).

---

## Layered Resolution Diagram

```mermaid
graph TB
    subgraph "Full Resolution Example for Telegram"
        I1["Built-in default\nstreaming=off\ntool_progress=off\nfooter=off"]
        I2["Tier 'edit' default\nstreaming=draft\ntool_progress=off\nfooter=off"]
        I3["Global override\ndisplay: {streaming: 'progress'}"]
        I4["Platform override\ndisplay.platforms.telegram:\n  footer: 'compact'"]
        RESULT["✅ Resolved Policy\nstreaming=progress\ntool_progress=off\nfooter=compact"]

        I1 -->|overridden by| I2
        I2 -->|overridden by| I3
        I3 -->|overridden by| I4
        I4 --> RESULT
    end

    classDef layer fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff

    class I1,I2,I3,I4 layer
    class RESULT result

Which option to choose?


Best Practices

Telegram in edit tier streams drafts which looks great; Email in batch tier correctly sends one final message. Only override when your use case genuinely differs from the tier default.
streaming="draft" edits the original message in place. On channels without edit support (WhatsApp, Email) it falls through to the tier default — but explicitly setting "draft" on a batch channel is a misconfiguration.
Config keys like "Telegram", "TELEGRAM", or "telegram" all resolve to the same platform. This makes YAML configs more natural.
Only specify what you need to change. A global display: { streaming: "progress" } applies to all platforms, then per-platform overrides layer on top for specific exceptions.

Messaging Bots

Deploy agents across Telegram, Slack, Discord, WhatsApp, and more

Platform Capabilities

What each channel can render

Display System

Terminal output and Rich rendering

Bot Streaming Replies

Configure streaming for individual bot sessions

Channel Capabilities

Platform capability flags and limits

Relay Transport

Route agent replies through an out-of-process connector