Skip to main content

Overview

Channels are Weaver’s abstraction for external communication platforms. They connect users to agents through messaging platforms like Telegram, Discord, Slack, and more.

Architecture

Channels communicate with agents via the message bus:

Channel Interface

From pkg/channels/base.go:
type Channel interface {
    Start(ctx context.Context) error
    Stop(ctx context.Context) error
    Send(ctx context.Context, msg bus.OutboundMessage) error
    IsRunning() bool
}
All channels implement this interface, providing uniform behavior:
1

Start

Initialize connection to the platform (WebSocket, HTTP polling, etc.)
2

Receive

Listen for incoming messages and publish to message bus
3

Send

Subscribe to outbound messages and forward to platform
4

Stop

Gracefully disconnect and cleanup resources

Supported Channels

Weaver supports a wide range of messaging platforms:

Configuration

{
  "channels": {
    "telegram": {
      "enabled": true,
      "token": "YOUR_BOT_TOKEN"
    }
  }
}

Features

  • Text messages with Markdown formatting
  • Voice message transcription (via Groq)
  • File uploads and downloads
  • Inline keyboards and buttons
  • Commands: /start, /help, /status

Bot Setup

  1. Talk to @BotFather on Telegram
  2. Create a new bot: /newbot
  3. Copy the token and add to config
  4. Start gateway: weaver gateway
Enable voice transcription by adding Groq API key in config:
{
  "providers": {
    "groq": {
      "api_key": "YOUR_GROQ_KEY"
    }
  }
}

Message Structure

Inbound Messages

From channels to agents:
type InboundMessage struct {
    Channel    string            // Channel name ("telegram", "discord")
    SenderID   string            // User/chat identifier
    ChatID     string            // Conversation identifier
    Content    string            // Message text
    SessionKey string            // Session for history
    Metadata   map[string]string // Extra context
}
Example:
msgBus.PublishInbound(bus.InboundMessage{
    Channel:    "telegram",
    SenderID:   "@username",
    ChatID:     "123456789",
    Content:    "What's the weather like?",
    SessionKey: "telegram:123456789",
})

Outbound Messages

From agents to channels:
type OutboundMessage struct {
    Channel string // Target channel
    ChatID  string // Target chat
    Content string // Message text
}
Example:
msgBus.PublishOutbound(bus.OutboundMessage{
    Channel: "telegram",
    ChatID:  "123456789",
    Content: "The weather is sunny, 72°F.",
})

Internal Channels

Weaver reserves special channel names for internal use:
const (
    ChannelCLI      = "cli"      // Direct agent invocation
    ChannelSystem   = "system"   // Subagent completions
    ChannelSubagent = "subagent" // Subagent context
    ChannelForge    = "forge"    // Forge Studio (code gen)
)
These channels:
  • Do not require external configuration
  • Are not dispatched to external platforms
  • Have special processing logic in the agent
Messages on internal channels are logged but never sent to external users.

Session Keys

Each conversation is tracked by a session key:
<channel>:<chat_id>
Examples:
  • telegram:123456789
  • discord:987654321
  • cli:default
  • rest:api-user-42
Session keys determine:
  • Which conversation history to load
  • Where to persist new messages
  • Which session to summarize when context is full

Voice Transcription

Channels can integrate voice transcription:
if transcriber != nil {
    if telegramChannel, ok := channelManager.GetChannel("telegram"); ok {
        if tc, ok := telegramChannel.(*channels.TelegramChannel); ok {
            tc.SetTranscriber(transcriber)
        }
    }
}
Voice messages are automatically:
  1. Downloaded from platform
  2. Sent to Groq Whisper API
  3. Transcribed to text
  4. Processed as normal messages
Groq transcription is fast (<1s for typical voice messages) and free for reasonable usage.

Channel Management

From the agent loop, channels can be managed via commands:
/list channels
Output:
Enabled channels: telegram, discord, slack
/show channel
Output:
Current channel: telegram

Custom Channels

Implement the Channel interface to add new platforms:
type MyChannel struct {
    bus     *bus.MessageBus
    config  MyChannelConfig
    running bool
}

func (c *MyChannel) Start(ctx context.Context) error {
    c.running = true
    go c.receiveLoop(ctx)
    return nil
}

func (c *MyChannel) receiveLoop(ctx context.Context) {
    for c.running {
        msg := c.pollPlatform()
        c.bus.PublishInbound(bus.InboundMessage{
            Channel:    "mychannel",
            SenderID:   msg.UserID,
            ChatID:     msg.ChatID,
            Content:    msg.Text,
            SessionKey: fmt.Sprintf("mychannel:%s", msg.ChatID),
        })
    }
}

func (c *MyChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
    return c.sendToPlatform(msg.ChatID, msg.Content)
}

func (c *MyChannel) Stop(ctx context.Context) error {
    c.running = false
    return nil
}

func (c *MyChannel) IsRunning() bool {
    return c.running
}
Register in channel manager:
myChannel := NewMyChannel(config, msgBus)
channelManager.RegisterChannel("mychannel", myChannel)

Message Bus Details

The message bus uses buffered channels for non-blocking communication:
type MessageBus struct {
    inbound  chan InboundMessage  // Buffer: 100
    outbound chan OutboundMessage // Buffer: 100
}
If a channel produces messages faster than the agent can process (>100/sec sustained), the bus will block. Monitor gateway logs for backpressure warnings.

Health Monitoring

Check channel status via REST API:
curl http://localhost:8080/ready
Response includes channel status:
{
  "status": "ready",
  "channels": {
    "telegram": {"enabled": true, "running": true},
    "discord": {"enabled": true, "running": true},
    "slack": {"enabled": true, "running": false}
  }
}

Next Steps

Gateway

Learn about gateway architecture

Configuration

Configure channel settings

Build docs developers (and LLMs) love