docs: add unified channel message flow architecture documentation
Comprehensive comparison of WhatsApp, Discord, and Gmail message flows: - Unified architecture overview showing shared components - Channel comparison matrix (connection, reception, routing, delivery) - Detailed sequence diagrams for each channel - Key files and functions for each step - Channel-specific features (threads, reactions, webhooks) - Data structure comparison (inbound messages, session keys) - Guide for adding new channels 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
12971e1283
commit
ab8177cbc0
769
docs/architecture/channel-message-flows.md
Normal file
769
docs/architecture/channel-message-flows.md
Normal file
@ -0,0 +1,769 @@
|
||||
# Channel Message Flow Architecture
|
||||
|
||||
This document describes how messages flow through Moltbot's channel system, comparing WhatsApp, Discord, and Gmail to highlight the unified architecture and channel-specific differences.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
All channels in Moltbot follow a common pattern:
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ External │ │ Channel │ │ Shared │ │ Pi Agent │
|
||||
│ Platform │───▶│ Adapter │───▶│ Router │───▶│ Framework │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
||||
▲ │
|
||||
│ │
|
||||
└────────────────────────────────────────────────────────┘
|
||||
Response Delivery
|
||||
```
|
||||
|
||||
### Shared Components (All Channels)
|
||||
|
||||
| Component | Location | Purpose |
|
||||
|-----------|----------|---------|
|
||||
| Agent Router | `src/routing/resolve-route.ts` | Routes messages to agents |
|
||||
| Reply Dispatcher | `src/auto-reply/reply/reply-dispatcher.ts` | Queues & delivers responses |
|
||||
| Agent Runner | `src/auto-reply/reply/get-reply.ts` | Sets up agent execution |
|
||||
| Pi Framework | `src/agents/pi-embedded-runner/` | Executes AI agents |
|
||||
| Outbound Service | `src/infra/outbound/` | Cross-channel delivery |
|
||||
|
||||
### Channel-Specific Components
|
||||
|
||||
| Channel | Adapter Location | Protocol |
|
||||
|---------|------------------|----------|
|
||||
| WhatsApp | `src/web/` | Baileys (WhatsApp Web) |
|
||||
| Discord | `src/discord/` | Carbon (@buape/carbon) |
|
||||
| Gmail | `src/hooks/` | Webhooks + gog CLI |
|
||||
| Telegram | `src/telegram/` | grammY |
|
||||
| Slack | `src/slack/` | Bolt |
|
||||
| Signal | `src/signal/` | signal-cli |
|
||||
| iMessage | `src/imessage/` | AppleScript/sqlite |
|
||||
|
||||
---
|
||||
|
||||
## Channel Comparison Matrix
|
||||
|
||||
### Connection Method
|
||||
|
||||
| Aspect | WhatsApp | Discord | Gmail |
|
||||
|--------|----------|---------|-------|
|
||||
| **Protocol** | WebSocket (Baileys) | WebSocket (Gateway) | HTTP Webhooks |
|
||||
| **Auth** | QR Code scan | Bot Token | OAuth2 (gog CLI) |
|
||||
| **Connection Type** | Persistent | Persistent | Push notifications |
|
||||
| **Library** | `@whiskeysockets/baileys` | `@buape/carbon` | `gog` CLI |
|
||||
| **Reconnect** | Auto with backoff | Auto with backoff | N/A (stateless) |
|
||||
|
||||
### Message Reception
|
||||
|
||||
| Aspect | WhatsApp | Discord | Gmail |
|
||||
|--------|----------|---------|-------|
|
||||
| **Event Source** | `messages.upsert` | `MESSAGE_CREATE` | Pub/Sub push |
|
||||
| **Debouncing** | Yes (configurable) | Yes (300ms default) | No |
|
||||
| **Deduplication** | By message ID | By message ID | By message ID |
|
||||
| **Media Download** | On reception | On demand | Via gog CLI |
|
||||
|
||||
### Routing & Gating
|
||||
|
||||
| Aspect | WhatsApp | Discord | Gmail |
|
||||
|--------|----------|---------|-------|
|
||||
| **Peer Types** | DM, Group | DM, Channel, Thread | Single inbox |
|
||||
| **Mention Required** | Configurable (groups) | Configurable | N/A |
|
||||
| **Allowlist** | Phone numbers | Users, Channels, Guilds | N/A |
|
||||
| **Session Key Format** | `agent:wa:phone:+1234` | `agent:discord:channel:123` | `hook:gmail:msgId` |
|
||||
|
||||
### Response Delivery
|
||||
|
||||
| Aspect | WhatsApp | Discord | Gmail |
|
||||
|--------|----------|---------|-------|
|
||||
| **Max Message Length** | ~65KB | 2000 chars | Unlimited |
|
||||
| **Chunking** | Markdown-aware | Markdown-aware | N/A |
|
||||
| **Media Support** | Image, Audio, Video, Doc | Image, Video, File | N/A (use gog) |
|
||||
| **Typing Indicator** | Yes | Yes | N/A |
|
||||
| **Reactions** | Limited | Full support | N/A |
|
||||
| **Threading** | Reply-to | Native threads | N/A |
|
||||
|
||||
---
|
||||
|
||||
## Detailed Flow Diagrams
|
||||
|
||||
### Unified Message Flow
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────────────────┐
|
||||
│ MOLTBOT UNIFIED MESSAGE FLOW │
|
||||
└────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ WhatsApp │ │ Discord │ │ Gmail │
|
||||
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ Baileys │ │ Carbon │ │ gog │
|
||||
│ Socket │ │ Client │ │ watch │
|
||||
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
||||
│ │ │
|
||||
│ WebSocket │ WebSocket │ HTTP POST
|
||||
▼ ▼ ▼
|
||||
┌────────────────────────────────────────────────────────────────────────────┐
|
||||
│ CHANNEL ADAPTER LAYER │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ monitorWebInbox │ │ DiscordMessage │ │ createHooksReq │ │
|
||||
│ │ () │ │ Listener │ │ Handler() │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ Extract: │ │ Extract: │ │ Extract: │ │
|
||||
│ │ - body │ │ - content │ │ - from │ │
|
||||
│ │ - sender │ │ - author │ │ - subject │ │
|
||||
│ │ - media │ │ - attachments │ │ - body │ │
|
||||
│ │ - group info │ │ - guild/channel │ │ - snippet │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
|
||||
└───────────┼────────────────────┼────────────────────┼───────────────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌────────────────────────────────────────────────────────────────────────────┐
|
||||
│ VALIDATION LAYER │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ checkInbound │ │ preflightDiscord│ │ validateToken │ │
|
||||
│ │ AccessControl() │ │ Message() │ │ () │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ - Allowlist │ │ - DM Policy │ │ - Hook token │ │
|
||||
│ │ - Group gating │ │ - Guild access │ │ - Path matching │ │
|
||||
│ │ - Mention check │ │ - Mention check │ │ │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
|
||||
└───────────┼────────────────────┼────────────────────┼───────────────────────┘
|
||||
│ │ │
|
||||
└────────────────────┼────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ROUTING LAYER (SHARED) │
|
||||
│ │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ resolveAgentRoute │ │
|
||||
│ │ () │ │
|
||||
│ └──────────┬──────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ Returns: │ │
|
||||
│ │ - agentId │ │
|
||||
│ │ - sessionKey │ │
|
||||
│ │ - channel │ │
|
||||
│ └──────────┬──────────┘ │
|
||||
└─────────────────────────────────┼───────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────────────┐
|
||||
│ AGENT LAYER (SHARED) │
|
||||
│ │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ getReplyFromConfig │ │
|
||||
│ │ () │ │
|
||||
│ └──────────┬──────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ runEmbeddedPiAgent │ │
|
||||
│ │ () │ │
|
||||
│ └──────────┬──────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ LLM Provider │ │
|
||||
│ │ (Claude/GPT/Gemini) │ │
|
||||
│ └──────────┬──────────┘ │
|
||||
└─────────────────────────────────┼───────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────────────┐
|
||||
│ DISPATCH LAYER (SHARED) │
|
||||
│ │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ createReplyDispatcher│ │
|
||||
│ │ () │ │
|
||||
│ └──────────┬──────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ Queue responses: │ │
|
||||
│ │ - Block replies │ │
|
||||
│ │ - Tool results │ │
|
||||
│ │ - Final reply │ │
|
||||
│ └──────────┬──────────┘ │
|
||||
└─────────────────────────────────┼───────────────────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────┼─────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌────────────────────────────────────────────────────────────────────────────┐
|
||||
│ DELIVERY LAYER │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ deliverWebReply │ │ deliverDiscord │ │ deliverOutbound │ │
|
||||
│ │ () │ │ Reply() │ │ Payloads() │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ - Chunk text │ │ - Chunk text │ │ - Route to last │ │
|
||||
│ │ - Send via │ │ - Send via REST │ │ known channel │ │
|
||||
│ │ Baileys │ │ - Add reactions │ │ - Or default │ │
|
||||
│ │ - Retry logic │ │ - Threading │ │ (WhatsApp) │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
|
||||
└───────────┼────────────────────┼────────────────────┼───────────────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
||||
│WhatsApp │ │ Discord │ │ Any Chan│
|
||||
│ Server │ │ Server │ │ nel │
|
||||
└─────────┘ └─────────┘ └─────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## WhatsApp Flow
|
||||
|
||||
### Sequence Diagram
|
||||
|
||||
```
|
||||
┌──────────┐ ┌─────────┐ ┌──────────┐ ┌────────┐ ┌────────┐ ┌─────────┐
|
||||
│ WhatsApp │ │ Baileys │ │ Monitor │ │ Router │ │ Agent │ │Dispatcher│
|
||||
└────┬─────┘ └────┬────┘ └────┬─────┘ └───┬────┘ └───┬────┘ └────┬────┘
|
||||
│ │ │ │ │ │
|
||||
│ message │ │ │ │ │
|
||||
│───────────▶│ │ │ │ │
|
||||
│ │ upsert │ │ │ │
|
||||
│ │──────────▶│ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ debounce │ │ │
|
||||
│ │ │───┐ │ │ │
|
||||
│ │ │◀──┘ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ route │ │ │
|
||||
│ │ │──────────▶│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ agentId │ │ │
|
||||
│ │ │◀──────────│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ (group?) check mention │
|
||||
│ │ │───┐ │ │ │
|
||||
│ │ │◀──┘ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ dispatch │ │ │
|
||||
│ │ │─────────────────────▶│ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ run Pi │
|
||||
│ │ │ │ │───┐ │
|
||||
│ │ │ │ │◀──┘ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ reply │
|
||||
│ │ │ │ │──────────▶│
|
||||
│ │ │ │ │ │
|
||||
│ │ │ deliver │ │ │
|
||||
│ │◀──────────────────────────────────────────────
|
||||
│ │ │ │ │ │
|
||||
│ send │ │ │ │ │
|
||||
│◀───────────│ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
```
|
||||
|
||||
### Key Files
|
||||
|
||||
| Step | File | Function |
|
||||
|------|------|----------|
|
||||
| Connect | `src/web/session.ts` | `createWaSocket()` |
|
||||
| Receive | `src/web/inbound/monitor.ts` | `monitorWebInbox()` |
|
||||
| Validate | `src/web/auto-reply/monitor/on-message.ts` | `createWebOnMessageHandler()` |
|
||||
| Route | `src/routing/resolve-route.ts` | `resolveAgentRoute()` |
|
||||
| Process | `src/web/auto-reply/monitor/process-message.ts` | `processMessage()` |
|
||||
| Execute | `src/agents/pi-embedded-runner/run.ts` | `runEmbeddedPiAgent()` |
|
||||
| Deliver | `src/web/auto-reply/deliver-reply.ts` | `deliverWebReply()` |
|
||||
|
||||
### WhatsApp-Specific Features
|
||||
|
||||
- **QR Code Auth**: First-time login requires scanning QR code
|
||||
- **Group Metadata**: Fetches participant list, subject, description
|
||||
- **Read Receipts**: Sends read receipts on message reception
|
||||
- **Location Messages**: Extracts latitude/longitude/address
|
||||
- **Reply Context**: Includes quoted message in context
|
||||
- **Presence Updates**: Shows "online" status
|
||||
|
||||
---
|
||||
|
||||
## Discord Flow
|
||||
|
||||
### Sequence Diagram
|
||||
|
||||
```
|
||||
┌──────────┐ ┌─────────┐ ┌──────────┐ ┌────────┐ ┌────────┐ ┌─────────┐
|
||||
│ Discord │ │ Carbon │ │ Listener │ │Preflight│ │ Agent │ │ Send │
|
||||
│ Gateway │ │ Client │ │ │ │ │ │ │ │ │
|
||||
└────┬─────┘ └────┬────┘ └────┬─────┘ └───┬────┘ └───┬────┘ └────┬────┘
|
||||
│ │ │ │ │ │
|
||||
│ READY │ │ │ │ │
|
||||
│───────────▶│ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ MESSAGE_ │ │ │ │ │
|
||||
│ CREATE │ │ │ │ │
|
||||
│───────────▶│ │ │ │ │
|
||||
│ │ handle │ │ │ │
|
||||
│ │──────────▶│ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ debounce │ │ │
|
||||
│ │ │───┐ │ │ │
|
||||
│ │ │◀──┘ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ preflight │ │ │
|
||||
│ │ │──────────▶│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ validate │ │
|
||||
│ │ │ │ - DM policy │
|
||||
│ │ │ │ - Guild access │
|
||||
│ │ │ │ - Mention req │
|
||||
│ │ │ │───┐ │ │
|
||||
│ │ │ │◀──┘ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ ok │ │ │
|
||||
│ │ │◀──────────│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ dispatch │ │ │
|
||||
│ │ │─────────────────────▶│ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ run Pi │
|
||||
│ │ │ │ │───┐ │
|
||||
│ │ │ │ │◀──┘ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ reply │
|
||||
│ │ │ │ │──────────▶│
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ │ chunk
|
||||
│ │ │ │ │ │──┐
|
||||
│ │ │ │ │ │◀─┘
|
||||
│ │ │ │ │ │
|
||||
│ REST │ │ │ │ │
|
||||
│◀──────────────────────────────────────────────────────────│
|
||||
│ │ │ │ │ │
|
||||
```
|
||||
|
||||
### Key Files
|
||||
|
||||
| Step | File | Function |
|
||||
|------|------|----------|
|
||||
| Connect | `src/discord/monitor/provider.ts` | `monitorDiscordProvider()` |
|
||||
| Listen | `src/discord/monitor/listeners.ts` | `DiscordMessageListener` |
|
||||
| Debounce | `src/discord/monitor/message-handler.ts` | `createDiscordDebouncer()` |
|
||||
| Validate | `src/discord/monitor/message-handler.preflight.ts` | `preflightDiscordMessage()` |
|
||||
| Process | `src/discord/monitor/message-handler.process.ts` | `processDiscordMessage()` |
|
||||
| Execute | `src/agents/pi-embedded-runner/run.ts` | `runEmbeddedPiAgent()` |
|
||||
| Deliver | `src/discord/monitor/reply-delivery.ts` | `deliverDiscordReply()` |
|
||||
| Send | `src/discord/send.outbound.ts` | `sendMessageDiscord()` |
|
||||
|
||||
### Discord-Specific Features
|
||||
|
||||
- **Guilds & Channels**: Multi-server support with per-channel config
|
||||
- **Threads**: Native thread support (public, private, forum)
|
||||
- **Reactions**: Add/remove reactions, ack reactions on processing
|
||||
- **Slash Commands**: Native Discord commands via `deployDiscordCommands()`
|
||||
- **Presence**: Optional presence/status monitoring
|
||||
- **Moderation**: Ban, kick, timeout, role management tools
|
||||
- **Embeds**: Rich embed support for responses
|
||||
- **2000 Char Limit**: Auto-chunking for long responses
|
||||
|
||||
---
|
||||
|
||||
## Gmail Flow
|
||||
|
||||
### Sequence Diagram
|
||||
|
||||
```
|
||||
┌──────────┐ ┌─────────┐ ┌──────────┐ ┌────────┐ ┌────────┐ ┌─────────┐
|
||||
│ Gmail │ │ gog │ │ Webhook │ │ Hook │ │ Cron │ │Outbound │
|
||||
│ Server │ │ watch │ │ Handler │ │Mapping │ │ Agent │ │ Deliver │
|
||||
└────┬─────┘ └────┬────┘ └────┬─────┘ └───┬────┘ └───┬────┘ └────┬────┘
|
||||
│ │ │ │ │ │
|
||||
│ New email │ │ │ │ │
|
||||
│───────────▶│ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ Pub/Sub │ │ │ │
|
||||
│ │ push │ │ │ │
|
||||
│ │──────────▶│ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ POST │ │ │
|
||||
│ │ │ /hooks/ │ │ │
|
||||
│ │ │ gmail │ │ │
|
||||
│ │ │───┐ │ │ │
|
||||
│ │ │◀──┘ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ validate │ │ │
|
||||
│ │ │ token │ │ │
|
||||
│ │ │───┐ │ │ │
|
||||
│ │ │◀──┘ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ match │ │ │
|
||||
│ │ │──────────▶│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ template │ │
|
||||
│ │ │ │ render │ │
|
||||
│ │ │ │───┐ │ │
|
||||
│ │ │ │◀──┘ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ dispatch │ │
|
||||
│ │ │ │─────────▶│ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ run Pi │
|
||||
│ │ │ │ │ (isolated)
|
||||
│ │ │ │ │───┐ │
|
||||
│ │ │ │ │◀──┘ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ deliver │
|
||||
│ │ │ │ │──────────▶│
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ │ route to
|
||||
│ │ │ │ │ │ last chan
|
||||
│ │ │ │ │ │──┐
|
||||
│ │ │ │ │ │◀─┘
|
||||
│ │ │ │ │ │
|
||||
└─────────────────────────────────────────────────◀─────────│
|
||||
(Response via WhatsApp/Discord/Telegram/etc)
|
||||
```
|
||||
|
||||
### Key Files
|
||||
|
||||
| Step | File | Function |
|
||||
|------|------|----------|
|
||||
| Watch | `src/hooks/gmail-watcher.ts` | `startGmailWatcher()` |
|
||||
| Receive | `src/gateway/server-http.ts` | `createHooksRequestHandler()` |
|
||||
| Match | `src/gateway/hooks-mapping.ts` | `applyHookMappings()` |
|
||||
| Template | `src/gateway/hooks-mapping.ts` | `renderTemplate()` |
|
||||
| Dispatch | `src/gateway/server/hooks.ts` | `dispatchAgentHook()` |
|
||||
| Execute | `src/cron/isolated-agent/run.ts` | `runCronIsolatedAgentTurn()` |
|
||||
| Deliver | `src/infra/outbound/deliver.ts` | `deliverOutboundPayloads()` |
|
||||
|
||||
### Gmail-Specific Features
|
||||
|
||||
- **Pub/Sub Push**: Uses Google Cloud Pub/Sub for real-time notifications
|
||||
- **gog CLI**: External CLI handles Gmail API, OAuth, watch registration
|
||||
- **Template Rendering**: `{{messages[0].from}}`, `{{messages[0].subject}}`
|
||||
- **Isolated Sessions**: Each email creates isolated agent session
|
||||
- **Cross-Channel Delivery**: Responses go to last-used channel (WhatsApp default)
|
||||
- **No Direct Reply**: Cannot reply to emails (use gog CLI tool if needed)
|
||||
- **Webhook Auth**: Token-based authentication for security
|
||||
|
||||
---
|
||||
|
||||
## Similarities Across Channels
|
||||
|
||||
### 1. Message Reception Pattern
|
||||
|
||||
All channels follow the same pattern:
|
||||
```typescript
|
||||
// Pseudocode - common pattern
|
||||
async function onMessage(rawMessage) {
|
||||
// 1. Extract normalized message
|
||||
const msg = extractMessage(rawMessage)
|
||||
|
||||
// 2. Debounce (optional)
|
||||
await debouncer.enqueue(msg)
|
||||
|
||||
// 3. Validate access
|
||||
if (!validateAccess(msg)) return
|
||||
|
||||
// 4. Route to agent
|
||||
const route = await resolveAgentRoute(msg)
|
||||
|
||||
// 5. Dispatch
|
||||
await dispatchToAgent(msg, route)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Shared Routing Logic
|
||||
|
||||
All channels use `resolveAgentRoute()` with the same interface:
|
||||
|
||||
```typescript
|
||||
// src/routing/resolve-route.ts
|
||||
interface RouteInput {
|
||||
channel: string // 'whatsapp' | 'discord' | 'gmail' | ...
|
||||
accountId: string // Account identifier
|
||||
peer: {
|
||||
kind: 'dm' | 'group' | 'channel' | 'hook'
|
||||
id: string // Phone, user ID, channel ID, etc.
|
||||
}
|
||||
}
|
||||
|
||||
interface ResolvedRoute {
|
||||
agentId: string
|
||||
sessionKey: string
|
||||
mainSessionKey: string
|
||||
matchedBy: string
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Shared Agent Execution
|
||||
|
||||
All channels ultimately call the same agent runner:
|
||||
|
||||
```typescript
|
||||
// src/agents/pi-embedded-runner/run.ts
|
||||
const result = await runEmbeddedPiAgent({
|
||||
sessionKey,
|
||||
message: userMessage,
|
||||
model,
|
||||
tools,
|
||||
onBlockReply,
|
||||
onToolResult,
|
||||
})
|
||||
```
|
||||
|
||||
### 4. Shared Reply Dispatcher
|
||||
|
||||
All channels use the same dispatcher pattern:
|
||||
|
||||
```typescript
|
||||
// src/auto-reply/reply/reply-dispatcher.ts
|
||||
const dispatcher = createReplyDispatcher({
|
||||
deliver: (payload) => channelSpecificDeliver(payload),
|
||||
onIdle: () => cleanup(),
|
||||
})
|
||||
|
||||
dispatcher.sendBlockReply(chunk)
|
||||
dispatcher.sendFinalReply(response)
|
||||
await dispatcher.waitForIdle()
|
||||
```
|
||||
|
||||
### 5. Common Configuration Structure
|
||||
|
||||
```json5
|
||||
{
|
||||
channels: {
|
||||
whatsapp: { /* channel-specific */ },
|
||||
discord: { /* channel-specific */ },
|
||||
},
|
||||
hooks: {
|
||||
gmail: { /* webhook-specific */ },
|
||||
},
|
||||
routing: {
|
||||
bindings: [
|
||||
// Shared routing rules
|
||||
],
|
||||
default: { agentId: 'main' }
|
||||
},
|
||||
agents: {
|
||||
// Shared agent config
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Differences
|
||||
|
||||
### 1. Connection Model
|
||||
|
||||
| Channel | Model | Implication |
|
||||
|---------|-------|-------------|
|
||||
| WhatsApp | Persistent WebSocket | Always connected, real-time |
|
||||
| Discord | Persistent WebSocket | Always connected, real-time |
|
||||
| Gmail | HTTP Webhooks | Stateless, push-based |
|
||||
|
||||
### 2. Authentication
|
||||
|
||||
| Channel | Auth Type | User Action Required |
|
||||
|---------|-----------|---------------------|
|
||||
| WhatsApp | QR Code | Scan with phone |
|
||||
| Discord | Bot Token | Create bot, copy token |
|
||||
| Gmail | OAuth2 | Create GCP project, authorize |
|
||||
|
||||
### 3. Message Threading
|
||||
|
||||
| Channel | Threading Model |
|
||||
|---------|-----------------|
|
||||
| WhatsApp | Reply-to (quote) |
|
||||
| Discord | Native threads, forums |
|
||||
| Gmail | Email threads (not used) |
|
||||
|
||||
### 4. Response Delivery
|
||||
|
||||
| Channel | Direct Reply | Cross-Channel |
|
||||
|---------|--------------|---------------|
|
||||
| WhatsApp | Yes | No |
|
||||
| Discord | Yes | No |
|
||||
| Gmail | No | Yes (always) |
|
||||
|
||||
### 5. Access Control
|
||||
|
||||
| Channel | Allowlist Granularity |
|
||||
|---------|-----------------------|
|
||||
| WhatsApp | Phone numbers, groups |
|
||||
| Discord | Users, channels, guilds, roles |
|
||||
| Gmail | N/A (single inbox) |
|
||||
|
||||
### 6. Rich Features
|
||||
|
||||
| Feature | WhatsApp | Discord | Gmail |
|
||||
|---------|----------|---------|-------|
|
||||
| Reactions | Limited | Full | No |
|
||||
| Threads | No | Yes | No |
|
||||
| Embeds | No | Yes | No |
|
||||
| Slash Commands | No | Yes | No |
|
||||
| Typing Indicator | Yes | Yes | No |
|
||||
| Read Receipts | Yes | No | No |
|
||||
| Media Upload | Yes | Yes | No |
|
||||
|
||||
---
|
||||
|
||||
## Data Structure Comparison
|
||||
|
||||
### Inbound Message
|
||||
|
||||
```typescript
|
||||
// WhatsApp
|
||||
interface WebInboundMsg {
|
||||
from: string // JID
|
||||
body: string
|
||||
chatType: 'dm' | 'group'
|
||||
senderE164: string
|
||||
groupSubject?: string
|
||||
mediaPath?: string
|
||||
replyToId?: string
|
||||
mentionedJids?: string[]
|
||||
}
|
||||
|
||||
// Discord
|
||||
interface DiscordInboundMsg {
|
||||
author: { id: string, username: string }
|
||||
content: string
|
||||
channelId: string
|
||||
guildId?: string
|
||||
attachments: Attachment[]
|
||||
referencedMessage?: Message
|
||||
mentions: User[]
|
||||
}
|
||||
|
||||
// Gmail (webhook payload)
|
||||
interface GmailHookPayload {
|
||||
messages: [{
|
||||
id: string
|
||||
from: string
|
||||
subject: string
|
||||
snippet: string
|
||||
body?: string
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Session Key Format
|
||||
|
||||
| Channel | Format | Example |
|
||||
|---------|--------|---------|
|
||||
| WhatsApp | `agent:<agentId>:whatsapp:<accountId>:dm:<phone>` | `agent:main:whatsapp:default:dm:+1234567890` |
|
||||
| WhatsApp Group | `agent:<agentId>:whatsapp:<accountId>:group:<jid>` | `agent:main:whatsapp:default:group:123@g.us` |
|
||||
| Discord DM | `agent:<agentId>:discord:<accountId>:user:<userId>` | `agent:main:discord:default:user:123456789` |
|
||||
| Discord Channel | `agent:<agentId>:discord:<accountId>:channel:<channelId>` | `agent:main:discord:default:channel:987654321` |
|
||||
| Gmail | `hook:gmail:<messageId>` | `hook:gmail:18a1b2c3d4e5f6` |
|
||||
|
||||
---
|
||||
|
||||
## Adding a New Channel
|
||||
|
||||
To add a new channel, implement these components:
|
||||
|
||||
### 1. Channel Adapter (Required)
|
||||
|
||||
```typescript
|
||||
// src/<channel>/monitor.ts
|
||||
export async function monitor<Channel>Channel(options: Options) {
|
||||
// Connect to platform
|
||||
const client = await connect()
|
||||
|
||||
// Register message handler
|
||||
client.on('message', async (raw) => {
|
||||
// Extract normalized message
|
||||
const msg = extractMessage(raw)
|
||||
|
||||
// Validate
|
||||
if (!validate(msg)) return
|
||||
|
||||
// Route
|
||||
const route = await resolveAgentRoute({
|
||||
channel: '<channel>',
|
||||
accountId: options.accountId,
|
||||
peer: { kind: msg.chatType, id: msg.peerId }
|
||||
})
|
||||
|
||||
// Dispatch
|
||||
await dispatchInboundMessage({
|
||||
ctx: buildContext(msg, route),
|
||||
deliver: (reply) => deliver<Channel>Reply(msg, reply),
|
||||
})
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Delivery Function (Required)
|
||||
|
||||
```typescript
|
||||
// src/<channel>/deliver.ts
|
||||
export async function deliver<Channel>Reply(
|
||||
msg: InboundMsg,
|
||||
reply: ReplyPayload
|
||||
) {
|
||||
// Chunk if needed
|
||||
const chunks = chunkText(reply.text, MAX_LENGTH)
|
||||
|
||||
// Send each chunk
|
||||
for (const chunk of chunks) {
|
||||
await client.send(msg.replyTo, chunk)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Channel Plugin (Optional)
|
||||
|
||||
```typescript
|
||||
// extensions/<channel>/src/channel.ts
|
||||
export const <channel>Plugin: ChannelPlugin = {
|
||||
id: '<channel>',
|
||||
name: '<Channel>',
|
||||
|
||||
async start(runtime) {
|
||||
await monitor<Channel>Channel(runtime.options)
|
||||
},
|
||||
|
||||
async stop() {
|
||||
await disconnect()
|
||||
},
|
||||
|
||||
async send(to, payload) {
|
||||
await sendMessage(to, payload)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Configuration Schema
|
||||
|
||||
```typescript
|
||||
// Add to config schema
|
||||
channels: {
|
||||
<channel>: {
|
||||
enabled: Type.Boolean(),
|
||||
token: Type.String(),
|
||||
// Channel-specific options
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [WhatsApp Message Flow](./whatsapp-message-flow.md)
|
||||
- [Gateway Architecture](./gateway.md)
|
||||
- [Agent Configuration](/configuration)
|
||||
- [Hooks System](/configuration#hooks)
|
||||
- [Channel Plugins](/extensions)
|
||||
Loading…
Reference in New Issue
Block a user