Skip to main content
Bot platform adapters now ship in the praisonai-bot package. praisonai bot serve still works exactly as documented here; for a standalone install see praisonai-bot Migration.
from praisonaiagents import Agent

agent = Agent(name="gateway-bot", instructions="Handle messages from Telegram, Slack, and Discord.")
agent.start("Set up the bot gateway for all chat platforms.")
The user messages on Telegram, Slack, or Discord; the gateway routes each channel to the right agent. Run all your bots from one command. The Gateway Server manages multiple bot connections and routes messages to the right AI agent. Parity with Bot(): praisonai gateway start now applies the same smart defaults as praisonai bot start, resolving the previous “zero tools in daemon mode” issue. Both entry points produce identical behavior with safe tools auto-injected and auto-approval enabled by default. Each channel bot gets an isolated agent via Agent.clone_for_channel() — fresh locks, fresh interrupt controller, and no shared handoffs state — so configuring tools or memory on one channel never leaks into another.

Quick Start

1

Install PraisonAI

pip install praisonai
2

Create gateway.yaml

Create a gateway.yaml file in your project (Gateway YAML files are read as UTF-8 — non-ASCII characters work on all platforms including Windows):
gateway:
  host: "127.0.0.1"
  port: 8765

agents:
  personal:
    instructions: "You are a helpful personal assistant"
    model: gpt-4o-mini
    tools:
      - internet_search
      - get_current_time
    reflection: true
  support:
    instructions: "You are a customer support agent"
    model: gpt-4o
    role: "Customer Support Specialist"
    goal: "Resolve customer issues quickly and accurately"
    backstory: "Expert in troubleshooting and customer care"
    tools:
      - internet_search
    tool_choice: auto
    allow_delegation: false

channels:
  telegram:
    token: ${TELEGRAM_BOT_TOKEN}
    streaming:
      mode: draft       # off | draft | progress — see /features/bot-streaming-replies
    routes:
      dm: personal
      group: support
      default: personal
  discord:
    token: ${DISCORD_BOT_TOKEN}
    routes:
      default: personal
3

Set Environment Variables

export TELEGRAM_BOT_TOKEN=your_telegram_token
export DISCORD_BOT_TOKEN=your_discord_token
export OPENAI_API_KEY="${OPENAI_API_KEY:?Set OPENAI_API_KEY in your shell}"
4

Start the Gateway

praisonai gateway start --config gateway.yaml
All bots start together. Messages are routed to the correct agent automatically.

Supported Channels

Telegram

Full support for DMs, groups, commands, voice, and media.

Discord

Guild channels, DMs, slash commands, and embeds.

Slack

Socket Mode, channels, DMs, slash commands, and threads.

WhatsApp

Cloud API and Web mode. DMs, groups, media support.
Windows users: Gateway Telegram error replies are automatically sanitized to ASCII-safe text — non-ASCII exception content (warning symbols, emoji, accented characters) no longer crashes the error handler with a charmap codec error. Real underlying errors (quota, rate limit, auth) surface cleanly.

Configuration Reference

Gateway Section

FieldTypeDefaultDescription
hoststring127.0.0.1Address to bind the gateway server
portinteger8765Port for the WebSocket server

Agents Section

Each agent is defined by a unique ID and its configuration:
agents:
  my_agent_id:
    instructions: "Your system prompt here"
    model: gpt-4o-mini
    memory: true
    tools:
      - internet_search
      - get_current_time
    reflection: true
    role: "Research Analyst"
    goal: "Find accurate information"
    backstory: "Expert researcher"
    tool_choice: auto
    allow_delegation: false
FieldTypeDefaultDescription
instructionsstring""System prompt for the agent
modelstringNoneLLM model (e.g., gpt-4o-mini, gpt-4o)
memorybooleanfalseEnable conversation memory
toolslist[]Tool names resolved via ToolResolver
reflectionbooleantrueEnable self-reflection / interactive mode
rolestringNoneAgent role (CrewAI-style)
goalstringNoneAgent goal (CrewAI-style)
backstorystringNoneAgent backstory (CrewAI-style)
tool_choicestringNoneauto, required, or none
allow_delegationbooleanfalseAllow task delegation to other agents

Channels Section

Each channel maps to a bot platform:
channels:
  telegram:
    token: ${TELEGRAM_BOT_TOKEN}    # Environment variable
    routes:
      dm: personal                   # DMs → personal agent
      group: support                 # Groups → support agent
      default: personal              # Fallback agent
Use ${ENV_VAR_NAME} syntax in token fields. The gateway automatically reads from your environment variables.

Channel Security

Each channel enforces the same access-control pipeline as standalone bots.
YAML KeyTypeDefaultPurpose
tokenstrrequired*Bot auth token. *Optional for whatsapp web mode and email/agentmail.
platformstrchannel nameOverride channel platform (e.g. telegram).
routing / routesdict{"default": "default"}Route map: dm, group, default → agent id.
allowed_userslist[str] | str[]User-ID allowlist. Comma-separated string also accepted (env-expansion friendly).
allowed_channelslist[str] | str[]Channel/group-ID allowlist. Same string handling.
group_policystr"mention_only"One of "mention_only", "command_only", "respond_all". Sets mention_required automatically.
auto_approve_toolsbool | strTrueAuto-approve safe tools. Strings "1"/"true"/"yes"/"on" are truthy.
default_toolslist[str](BotConfig default)Per-channel override for default safe tools.
channels:
  telegram_support:
    token: ${TELEGRAM_BOT_TOKEN}
    allowed_users:                # User-ID allowlist (empty list → unknown_user_policy decides)
      - "123456789"
      - "987654321"
    allowed_channels:             # Group/channel allowlist (empty = anywhere)
      - "-1001234567890"
    group_policy: "mention_only"  # mention_only | command_only | respond_all
    auto_approve_tools: true      # Auto-approve safe tools (default true)
    routes:
      dm: personal
      group: support
      default: personal
allowed_users interacts with unknown_user_policy. With an empty allowed_users list, every Telegram user is treated as “unknown” and the unknown_user_policy decides their fate:
  • "deny" (default) — all messages silently dropped (recommended for production).
  • "pair" — unknown users go through the owner-approval pairing flow.
  • "allow" — every user is let through (only set this in trusted networks).
Earlier releases incorrectly treated empty allowed_users as “allow everyone” on Telegram, bypassing the policy entirely. Fixed in PR #1885. Discord and Slack were already correct.
As of PR #1791, gateway-mode bots enforce the same security pipeline as standalone bots (praisonai bot start). Previous versions silently bypassed allowed_users, pairing, and group_policy in gateway mode.
Pair with unknown_user_policy: "deny" for the most secure default. To intentionally allow everyone (e.g. internal staging), leave allowed_users empty and set unknown_user_policy: "allow" — both are required.

Interactive presentations (optional)

GatewayMessage carries an optional presentation: MessagePresentation field. When set, channel adapters that implement SupportsPresentation render it as a native widget (Telegram inline keyboard, Slack Block Kit, Discord components). Channels that do not implement the protocol fall back to the message’s plain-text content. See Interactive Bot Messages for the full presentation model.

Hot-Reload

Editing gateway.yaml while the gateway runs triggers a diff-driven reload — only affected agents or channels restart. The WebSocket server stays up. See Gateway Hot-Reload for the full restart-scope table.

CLI Commands

praisonai gateway start --config gateway.yaml
praisonai gateway start --config gateway.yaml --host 0.0.0.0 --port 9000
praisonai gateway status

Python Usage

from praisonai.gateway import WebSocketGateway

# Load gateway config, agents, and channels from YAML
gateway = WebSocketGateway.from_config_file("gateway.yaml")

import asyncio
asyncio.run(gateway.start())
from_config_file() automatically resolves ${ENV_VAR} syntax in your YAML, creates agents with tools, and configures channel bots.
The gateway exposes a health endpoint at http://host:port/health:
curl http://127.0.0.1:8765/health
Returns:
{
  "status": "healthy",
  "uptime": 120.5,
  "agents": 2,
  "sessions": 3,
  "clients": 1,
  "channels": {
    "telegram": {
      "platform": "telegram",
      "running": true
    },
    "discord": {
      "platform": "discord", 
      "running": false
    }
  },
  "push": {
    "enabled": true,
    "push_channels": 2,
    "online_clients": 5,
    "redis_connected": true
  }
}
The push section is only included when push notifications are enabled.
The gateway calls _create_bot() to build independent clones for each channel:Each clone has fresh locks and interrupt controllers, preventing cross-channel interference. Learn more about Agent Cloning.
You can still run a single bot without the gateway:
praisonai bot telegram --token $TELEGRAM_BOT_TOKEN
This starts just one bot connected to a single agent — no gateway needed.
Never commit bot tokens to version control. Always use environment variables or a .env file.

BotOS Options

When creating a BotOS instance in Python, the following options control gateway-level behaviour:
FieldTypeDefaultDescription
botslist[Bot][]Pre-built Bot instances to orchestrate
agentAgentNoneShared agent for auto-created bots (used with platforms)
platformslist[str]NonePlatform names; creates one Bot per platform using the shared agent
health_monitorHealthMonitorConfigNoneChannel health monitoring configuration
enable_supervisionboolTrueEnable automatic channel supervision and recovery
idle_policyGatewayIdlePolicyProtocolNoneWhen set, schedules an idle-dormancy loop that quiesces transports after inactivity. Default None = always-on. See Scale-to-Zero Gateway.
from praisonaiagents import Agent
from praisonai.bots import BotOS, Bot
from praisonaiagents.gateway import ScaleToZeroPolicy

agent = Agent(name="assistant", instructions="Help users")

botos = BotOS(
    bots=[Bot("telegram", agent=agent)],
    idle_policy=ScaleToZeroPolicy(
        idle_timeout_minutes=5,
        wake_url="https://my-bot.fly.dev/_wake",
    ),
)
botos.run()

Observability

Gateway Metrics

Scrape GET /metrics for Prometheus-format counters and gauges on every hop of the message flow — no extra dependencies.

Correlation IDs

One stable id joins ingress, session, and agent-run logs for every turn. Read it inside any tool with current_correlation_id().

Gateway Tracing Hook

Open a distributed-tracing span around each pipeline stage — inbound, admit, agent.run, llm.call, tool.call, outbox.enqueue, delivery.

Code-Skew Guard

After running git pull or pip install -U, the gateway’s /model command detects that the installed code version has changed and blocks the model switch with a “restart required” message. This prevents the model from changing when the running code is out of sync with the installed libraries. To opt out (useful in development):
session_manager.code_skew_guard = False
Helpers for custom tooling:
from praisonaiagents.gateway import detect_code_skew, read_code_fingerprint

fingerprint = read_code_fingerprint()
if detect_code_skew(fingerprint):
    print("Code has changed since gateway started — restart recommended")

Best Practices

Leave allowed_users empty only with unknown_user_policy: "deny" for production. Pairing mode is fine for personal bots; public gateways need explicit allowlists.
Map dm, group, and default to different agents when support and personal assistants should not share memory or tools. Isolated clones prevent cross-channel leakage.
Reference tokens as ${TELEGRAM_BOT_TOKEN} in YAML — never commit secrets. Gateway resolves env vars at load time on all platforms including Windows.
Poll the health endpoint during deploys and wire Gateway Metrics into Prometheus for message-flow visibility.

Bind-Aware Auth

Token auth and loopback bypass for gateway operational endpoints.

Gateway Error Handling

Supervision, restarts, and error recovery in the gateway.

Gateway Metrics

Prometheus-format message-flow metrics from GET /metrics.

Correlation IDs

Join ingress, session, and agent-run logs on one stable id per message.