Skip to content

Channels

Channels is a multi-platform messaging adapter system that connects AI agents to WhatsApp, Telegram, Discord, Slack, Signal, Microsoft Teams, and iMessage. Each adapter handles platform-specific webhook processing, message normalization, and response delivery, so you write your agent logic once and deploy it to any messaging platform.

Why Channels Exists

Every messaging platform has its own API, authentication mechanism, webhook format, message length limits, and rate limiting rules. Building a Telegram bot is completely different from building a WhatsApp integration. Channels abstracts these differences behind a single interface.

Your agent receives normalized messages and sends plain text or Markdown responses. The adapter handles everything else: webhook verification, long-polling, WebSocket connections, message splitting, format conversion, and platform-specific quirks.

Supported Platforms

PlatformTransportAuthStatus
WhatsAppWebhook (Cloud API)OAuth access tokenAvailable
TelegramLong-polling (Bot API)Bot tokenAvailable
DiscordWebSocket (Gateway)Bot tokenAvailable
SlackSocket ModeBot + App tokensAvailable
Signalsubprocess (signal-cli)Account numberAvailable
Microsoft TeamsWebhook (Graph API)App ID + passwordAvailable
iMessageAppleScript (Messages.app)Apple IDAvailable (macOS only)

Architecture

                Messaging Platform


              ┌─────────────────┐
              │  Channel Adapter │  (platform-specific)
              │  - Webhook/WS   │
              │  - Auth          │
              │  - Normalize     │
              └────────┬────────┘


              ┌─────────────────┐
              │  Channel Manager │  (platform-agnostic)
              │  - Session map   │
              │  - Message routing│
              │  - Retry logic   │
              └────────┬────────┘


              ┌─────────────────┐
              │     Engine       │
              │  ProcessMessage  │
              │  ForWeb()        │
              └─────────────────┘

ChannelAdapter Interface

Every adapter implements:

go
type ChannelAdapter interface {
    Name() string
    Start(ctx context.Context) error
    Stop() error
    SendMessage(chatID string, message *ChannelMessage) error
    IsConfigured() bool
}

Channel Manager

The Manager handles adapter lifecycle and message routing:

  • Session mapping: Maps adapter:chatID pairs to session IDs. Each chat gets a persistent session.
  • Message routing: Calls engine.ProcessMessageForWeb() with a responseCollector that aggregates streaming events into a final response string.
  • Retry logic: Adapters that fail on startup are retried up to 5 times with 30-second delays.
  • Session reset: The /new command in any platform creates a fresh session for that chat.

Message Normalization

Incoming messages from all platforms are reduced to a string of text content. The Manager routes this to the Engine pipeline. The Engine's response (collected from streaming events) is sent back through the adapter's SendMessage method.

Message Splitting

Platform message length limits vary:

PlatformMax Length
Telegram4,096 characters
WhatsApp4,096 characters
Discord2,000 characters
Slack4,096 characters

SplitMessage() splits long responses at paragraph boundaries (newlines, then spaces) to stay within limits. Each chunk is sent as a separate message.

Standalone Value

The channels module can be used independently of the rest of OpenParallax. Import it, configure an adapter, and connect it to any message handler:

go
import "github.com/openparallax/openparallax/internal/channels"
import "github.com/openparallax/openparallax/internal/channels/telegram"

You provide the engine integration (or any message handler that implements the routing interface). The adapter handles all platform-specific concerns.

Configuration

All channel adapters are configured in config.yaml under the channels section:

yaml
channels:
  telegram:
    enabled: true
    token_env: TELEGRAM_BOT_TOKEN
    allowed_users: [123456789]

  whatsapp:
    enabled: true
    phone_number_id: "1234567890"
    access_token_env: WHATSAPP_ACCESS_TOKEN
    verify_token: "my-verify-token"
    webhook_port: 9443
    allowed_numbers: ["+1234567890"]

  discord:
    enabled: true
    token_env: DISCORD_BOT_TOKEN
    allowed_channels: ["channel-id-1"]
    respond_to_mentions: true

  slack:
    enabled: true
    bot_token_env: SLACK_BOT_TOKEN
    app_token_env: SLACK_APP_TOKEN

  signal:
    enabled: true
    cli_path: /usr/local/bin/signal-cli
    account: "+1234567890"
    allowed_numbers: ["+0987654321"]

  teams:
    enabled: true
    app_id_env: TEAMS_APP_ID
    password_env: TEAMS_APP_PASSWORD

  imessage:
    enabled: true             # macOS only
    apple_id: "you@icloud.com"

API keys and tokens are read from environment variables, never stored in the config file.

Slash Commands

All adapters support platform-specific versions of the slash commands:

CommandAction
/newReset the session for this chat
/otrStart an Off-The-Record session
/helpShow available commands (Telegram)
/statusShow agent status (Telegram)

The adapter intercepts these commands before routing to the engine.

Security

Access Control

Every adapter supports an allow-list to restrict who can interact with the agent:

  • WhatsApp: allowed_numbers (phone numbers)
  • Telegram: allowed_users (user IDs)
  • Discord: allowed_channels and allowed_users (Discord IDs)
  • Signal: allowed_numbers (phone numbers)

Messages from unauthorized users are logged and silently dropped (or receive a "This agent is private" response on Telegram).

Rate Limiting

Telegram includes built-in rate limiting (30 messages per minute per user). Other adapters rely on platform-level rate limiting.

OTR Mode

All adapters support OTR mode via the /otr command. OTR sessions use in-memory storage only and do not persist to SQLite. Tool access is restricted (no filesystem writes, no memory persistence).