Architecture: How should channel adapters for Telegram, Slack, and Discord...

Documentation for Sessions

🏗️ Architecture: How should channel adapters for Telegram, Slack, and Discord...

Date: 2026-03-21
Time: 17:13:31 UTC
Session: gspace1-250.3
Agent: backend
Confidence: 92%
Status: ✅ Documented


📋 Decision Context

Question:

How should channel adapters for Telegram, Slack, and Discord be implemented — send directly from adapter or return payloads for the gateway?

Task: S250: Channel adapters for Telegram, Slack, Discord rich messages


🎯 Decision Made

Chosen:

Hybrid approach: Telegram adapter sends directly via fetch() (returns alreadySent: true, like WhatsApp adapter), while Slack and Discord adapters return structured payloads (returns alreadySent: false, like Teams adapter). Gateway detects adapter payloads via JSON.parse and skips its own formatForSlack()/formatForDiscord() when adapter has already composed the message.

Options Considered:

  1. All adapters send directly (consistent but duplicates gateway logic)
  2. All adapters return payloads (consistent but requires gateway refactor for Telegram)
  3. Hybrid based on gateway capability (chosen — minimal changes, follows existing patterns)

💭 Reasoning

Two patterns already exist in the codebase: (1) WhatsApp adapter sends directly because Twilio Content API requires specific API calls the gateway can't generalize, (2) Teams adapter returns Adaptive Card JSON because the gateway's sendTeamsMessage() already knows how to send arbitrary payloads. For new adapters: Telegram's gateway sendTelegramMessage() only supports plain text (no reply_markup param), so the adapter must send directly. Slack's gateway sendSlackMessage() already calls formatForSlack() which produces Block Kit — the adapter just needs to provide pre-composed blocks that bypass formatForSlack(). Same for Discord — formatForDiscord() produces embeds, but components need different payload structure. The gateway methods detect adapter payloads by attempting JSON.parse on response.text and checking for blocks (Slack) or components (Discord) keys. This avoids refactoring existing gateway methods while supporting rich messages.


📁 Files Involved


🔗 Related


Auto-generated by MCP Smart Consolidation