Skip to main content
Push outbound messages from an agent-backed bot — reply to the requesting chat, a home channel, or a named alias.
import asyncio
from praisonai.bots import BotOS, Bot, SessionSource
from praisonaiagents import Agent

agent = Agent(name="ops", instructions="Alert humans about incidents.")
botos = BotOS(bots=[Bot("telegram", agent=agent)])

botos.configure_channels({
    "telegram": {"home_channel": "123456", "aliases": {"ops-alerts": "123456"}},
})

async def notify():
    src = SessionSource(platform="telegram", channel_id="123456")
    await botos.deliver("origin", "Build finished!", origin=src)

asyncio.run(notify())
The user triggers an alert; BotOS delivers the agent’s message to the target channel.

Quick Start

1

Simple Usage

Reply to where the request came from:
import asyncio
from praisonai.bots import BotOS, Bot, SessionSource
from praisonaiagents import Agent

agent = Agent(name="ops", instructions="Send status updates.")
botos = BotOS(bots=[Bot("telegram", agent=agent)])

async def notify():
    src = SessionSource(platform="telegram", channel_id="123456")
    await botos.deliver("origin", "Build finished!", origin=src)

asyncio.run(notify())
2

With Configuration

Set home channels and deliver by alias:
botos.configure_channels({
    "telegram": {"home_channel": "123456", "aliases": {"ops-alerts": "123456"}},
})

await botos.deliver("telegram", "Nightly digest ready")
await botos.deliver("ops-alerts", "Disk usage at 90%")

How It Works

TargetResolves to
originChat that triggered the request (origin=SessionSource(...))
<platform>Platform home channel from /sethome or config
<platform>:<id>Explicit channel ID
<alias>Friendly name from configure_channels or overlay file
Resolution order: originplatform:id → bare platform → alias. Platform names win over aliases. Home and observed channels persist to ~/.praisonai/state/channel_directory.json.

Configuration Options

YAML

channels:
  telegram:
    token: ${TELEGRAM_BOT_TOKEN}
    home_channel: "123456"
    aliases:
      ops-alerts: "123456"

Alias overlay

Pre-name channels in ~/.praisonai/state/channel_aliases.json:
{
  "engineering": { "platform": "discord", "channel_id": "555" },
  "ops": "slack:C111"
}
Call botos.delivery_router.refresh_directory() periodically so adapters enumerate channels the bot has not yet heard from.

Rate Limiting

Scheduled and background sends share the reply-path rate limiter automatically — no config change required. Scheduled sends also fire at most once per due window across multiple BotOS processes — see BotOS → Multi-Process / HA Deployments.
You callWhat happens
botos.deliver("ops-alerts", "...")Rate-limited per platform via the shared reply-path rate limiter.
botos.deliver("ops-alerts", "...", origin=source)Rate-limited with origin context; used for targeted proactive replies.
Adapter’s send_message() returns FalseTreated as a transient failure. Dead-target flag not tripped. Safe to retry.
# Scheduled daily digest — proactive send to a named channel
await botos.deliver(
    "ops-alerts",
    "Nightly digest ready",
)
# Targeted proactive send with origin context
await botos.deliver(
    "ops-alerts",
    "Build finished",
    origin=source,
)

Best Practices

Aliases survive renumbering and read better in logs.
Bare-platform targets fail without a configured home channel.
telegram as an alias will never resolve — platform lookup wins.
deliver() returns False on resolution or send failure — log and retry as needed.
BotOS.deliver rate-limits sends via the shared reply-path rate limiter, but does not support idempotency deduplication. For dedup across retries or workers, use the reply-path delivery.send(...) outbox (see Durable Delivery).

BotOS

Multi-platform orchestration

Bot Gateway

Run multiple bots from one server