praisonai-bot package. praisonai bot serve still works exactly as documented here; for a standalone install see praisonai-bot Migration.streaming: true is a shortcut. For unified per-platform defaults and overrides, use Display Policy.TypeError: achat() got an unexpected keyword argument 'stream_callback'. Upgrade to the latest release if you hit that error.Quick Start
How It Works
agent.stream_emitter, not as a stream_callback kwarg to astart(). The bot adds a temporary callback for the duration of the run and removes it on completion (and on timeout/cancel).| Component | Purpose | Responsibility |
|---|---|---|
DraftStreamer | Manages live updates | Coalesces edits, respects rate limits |
BotAdapter | Platform interface | Sends/edits messages |
StreamingConfig | User preferences | Timing, text, mode settings |
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
streaming | bool | False | Enable progressive streaming — bot sends a placeholder then edits it live as the agent produces tokens |
stream_edit_interval_ms | int | 700 | Minimum milliseconds between message edits (respects platform rate limits) |
Per-channel streaming support
| Channel | Live edits | Default edit interval | Text limit |
|---|---|---|---|
| Telegram | Yes | platform default | 4096 |
| Slack | Yes | 1.0s | 40000 |
| Discord | Yes | platform default | 2000 |
| No (single message) | — | 4096 | |
| No (single message) | — | unlimited |
Advanced configuration (StreamingConfig)
Forprogress mode, custom placeholder text, or fine-grained min_delta control, use the lower-level StreamingConfig API.
Streaming Modes
Three modes are available to match different use cases:| Mode | Behavior | Best For |
|---|---|---|
off | Single final message after completion | Default behavior, zero impact |
draft | Progressive edits with growing answer | Long responses, platforms like Telegram |
progress | Tool status updates, then final answer | Tool-heavy agents, user wants progress |
draft mode) works on Telegram, Slack, and Discord — each adapter honours its own edit_rate_limit and text_limit from Channel Capabilities. WhatsApp and Email fall back to a single final message (live_edit=False). The simple streaming: true / --stream form enables draft mode automatically.StreamingConfig options
| Option | Type | Default | Description |
|---|---|---|---|
mode | StreamingMode | StreamingMode.OFF | Streaming mode: OFF, DRAFT, or PROGRESS |
min_interval | float | 1.5 | Minimum seconds between message edits (rate-limit safe) |
min_delta | int | 120 | Minimum new characters in the buffer before an edit fires |
placeholder_text | str | "🤔 Thinking..." | Initial message text sent before any content arrives |
progress_prefix | str | "🤔 " | Prefix used in progress mode tool-status updates |
progress_style | str | "line" | Progress-mode rendering style: "line" (single overwritten tool label, unchanged default) or "feed" (bounded multi-line rolling status feed with per-step ⏳/✓/✗ glyphs) |
progress_max_lines | int | 8 | Max trailing lines shown when progress_style="feed"; older lines scroll off the top of the window |
progress_max_line_chars | int | 120 | Per-line character cap in feed style (includes the leading glyph); words are truncated at a boundary with an ellipsis |
disable_progressive_edits_after | int | 3 | Consecutive recoverable edit failures before progressive editing is turned off for the rest of the stream — the completed answer is then delivered as a single final send |
flood_backoff_factor | float | 2.0 | Multiplier applied to the edit interval on each recoverable (flood / 429 / transient) failure |
max_interval | float | 30.0 | Cap in seconds for the adaptively widened edit interval — backoff stops growing past this |
strip_reasoning_tags | bool | True | Strip <think>…</think> and <reasoning>…</reasoning> spans from streamed and final output. Default ON — set to false to opt out |
Progress feed style
Setprogress_style: feed to render tool calls as a bounded rolling multi-line status view instead of a single overwritten label.
A research agent on Telegram chains web_search, fetch_url, and summarize. With the default progress_style="line", each tool overwrites the last, so a failed fetch_url vanishes. With feed, every step keeps its own line and outcome glyph:
⏳ running, ✓ done, ✗ error — instead of one label that overwrites itself.
When to use which style
How one tool flows through the feed
A tool’s start event and its matching finish event share one correlation id, so the line updates in place instead of duplicating.feed style activates only when mode: progress and progress_style: feed. The default progress_style="line" preserves the existing single-line behaviour bit-for-bit — feed is strictly opt-in per channel.Flood-control
Your Telegram bot is streaming a long answer during peak hours. Telegram starts returning 429 after the third edit. The streamer doubles its edit interval (1.5s → 3s → 6s → capped atmax_interval). After disable_progressive_edits_after consecutive failures it stops editing entirely and waits — when finalize() fires it delivers the completed answer as a fresh message. The user never sees a stuck placeholder, never sees a partial reply, and the rest of your bot’s chats are unaffected because the backoff is per-stream.
_current_min_interval is mutated on the stream instance, not the shared StreamingConfig. A flood in one chat will never slow streaming in another.| Event | What the streamer does |
|---|---|
| Recoverable edit failure (flood / 429 / transient) | fail_streak += 1; current_min_interval *= flood_backoff_factor (capped at max_interval). Per-stream — does not mutate the shared StreamingConfig |
fail_streak >= disable_progressive_edits_after | Progressive editing turns OFF for the rest of this stream. Subsequent token events skip _perform_update. The placeholder is left in place until finalize() |
| Non-recoverable edit failure | Logged at WARNING. Fail streak does NOT increment; progressive stays enabled |
| Successful edit | fail_streak resets to 0 (recovery) |
finalize(final_content) | Strip reasoning tags (if enabled), try edit-in-place, fall back to send_message if edit fails |
Reasoning-tag filtering
Default ON.<think> and <reasoning> spans (case-insensitive, multi-line) are stripped from both streamed and final output. A trailing unclosed opening tag is also dropped so internal reasoning never leaks mid-stream while a block is still being produced. Set strip_reasoning_tags: false to opt out (for example, on a reasoning-transparency bot).
YAML vs Python vs CLI
YAML Configuration
Add to yourbot.yaml under the channel configuration:
Python API
Configure streaming programmatically with theconfigure_streaming() method:
Manual Streamer Usage
For advanced use cases, you can useDraftStreamer directly:
Best Practices
Start with `--stream` — tune `stream_edit_interval_ms` only if needed
Start with `--stream` — tune `stream_edit_interval_ms` only if needed
700ms interval works well on Telegram. If you hit “message is not modified” or 429 errors on a shared/busy channel, raise it to 1000–2000. On Discord (stricter limits), prefer 2000 or use the advanced StreamingConfig form.Tune min_interval to your platform's edit rate limit
Tune min_interval to your platform's edit rate limit
chat_update API is more generous. Set min_interval to match your platform’s limits to avoid 429 errors.Use progress mode for tool-heavy agents
Use progress mode for tool-heavy agents
progress mode keeps users informed about what’s happening instead of showing a static “thinking” message.Use `feed` when your agent chains many tools
Use `feed` when your agent chains many tools
progress_style: feed turns a black-box “still thinking…” indicator into a live per-step audit trail. Every tool call keeps its own line with a ⏳/✓/✗ glyph, so users see which step failed instead of watching one label overwrite itself. See the line-vs-feed comparison.Keep `progress_max_lines` small on mobile channels
Keep `progress_max_lines` small on mobile channels
progress_max_lines to 4–6 so the feed stays readable — older lines scroll off the top of the window while the newest steps stay visible.Streaming is off by default — opt in per channel
Streaming is off by default — opt in per channel
streaming: configuration will use the new behavior. All other channels continue with the original single-message approach.Final delivery is guaranteed even when edits are flooded
Final delivery is guaranteed even when edits are flooded
finalize() runs, the streamer first tries to edit the placeholder with the full answer. If that edit fails (or progressive editing was already disabled by a flood-control strike), the streamer falls back to a fresh send_message so you always receive the completed answer. No stale ”🤔 Thinking…” placeholder is left behind.Troubleshooting
Used to see `<think>` or `<reasoning>` spans in your chat?
Used to see `<think>` or `<reasoning>` spans in your chat?
praisonai to get the fix automatically.Bot reply got stuck mid-edit on a busy chat?
Bot reply got stuck mid-edit on a busy chat?
disable_progressive_edits_after / flood_backoff_factor / max_interval per channel if your platform’s rate limits differ.My `progress_style: feed` config was rejected at startup
My `progress_style: feed` config was rejected at startup
"line" or "feed". Any other value raises Invalid progress_style '<v>'. Must be one of: feed, line at load time. Check for typos like feeds or multiline.An errored tool still shows the ✓ glyph
An errored tool still shows the ✓ glyph
error (✗) the compositor never downgrades it to done (✓), and a late done event never overwrites an error. If you ever see this, please file a bug against praisonai.
