Канали
WhatsApp
Адаптер WhatsApp використовує офіційний Meta WhatsApp Business Cloud API (graph.facebook.com/v18.0). Вхідні повідомлення приходять через Meta webhooks; вихідні відправляються через REST-виклики до Cloud API.
Плагіни каналів читають свою рантайм-конфігурацію через app.channelService. Поточна реалізація — EnvChannelService на базі env-змінних; вона віддає один дефолтний WhatsApp-канал і один дефолтний Telegram-канал. Інтерфейс готовий до майбутньої мультиканальної реалізації з БД.
Архітектура
src/channels/whatsapp/
├── index.ts # Service factory (WhatsAppService)
├── plugin.ts # Fastify plugin (routes)
├── connection.ts # Cloud API client, webhook parsing, token lifecycle
├── handler.ts # Transport normalization + AgentTask creation
├── sender.ts # Rate-limited outbound sender
├── queue.ts # BullMQ inbound/outbound workers
├── auth-state.ts # OAuth token persistence in Redis
├── conversation-repository.ts # Prisma conversation store
└── types.ts # Config and message types
Конфігурація
| Змінна | За замовчуванням | Опис |
|---|---|---|
WHATSAPP_APP_ID | — | Meta app ID (використовується для оновлення токена) |
WHATSAPP_APP_SECRET | — | Meta app secret (використовується для оновлення токена) |
WHATSAPP_PHONE_NUMBER_ID | — | Phone number ID з дашборду Meta Business |
WHATSAPP_ACCESS_TOKEN | — | Початковий OAuth access token |
WHATSAPP_WEBHOOK_VERIFY_TOKEN | — | Webhook verify token (задається в дашборді Meta) |
WA_PHONE_NUMBER | +380000000000 | Номер телефону відправника (як префікс Redis-ключа) |
WA_RATE_LIMIT_PER_MIN | 60 | Макс вихідних повідомлень на хвилину |
Налаштування
- Створіть Meta-застосунок з увімкненим продуктом WhatsApp Business.
- Додайте номер телефону і запамʼятайте Phone Number ID у дашборді.
- Згенеруйте long-lived access token і задайте
WHATSAPP_ACCESS_TOKEN. - Задайте
WHATSAPP_WEBHOOK_VERIFY_TOKENі налаштуйте webhook URL у дашборді Meta:- Verify endpoint:
GET /api/v1/whatsapp/webhook - Events endpoint:
POST /api/v1/whatsapp/webhook
- Verify endpoint:
- Задайте решту env-змінних і запустіть сервер.
Життєвий цикл підключення
- Сервер стартує; викликається
WhatsAppConnection.connect(). - Збережений токен підтягується з Redis. Якщо його нема — сконфігурований
WHATSAPP_ACCESS_TOKENзберігається в Redis. - Якщо термін дії збереженого токена спливає протягом 7 днів — він обмінюється на новий long-lived token через Meta Graph API.
- Проактивна перевірка виконується кожні 6 годин для ранньої ротації токенів.
- При шатдауні скидається refresh-планувальник.
Сканування QR не потрібне — автентифікація повністю через OAuth-токени.
Потік повідомлень
Вхідний
- Meta шле POST на
/api/v1/whatsapp/webhook. - Payload парситься у
connection.ts(handleWebhookPayload). - Кожне повідомлення витягується і передається зареєстрованим обробникам.
- Обробник ставить повідомлення у
wa-inbound(BullMQ). - Воркер:
- шукає/створює User і Conversation за WhatsApp JID;
- зберігає вхідне повідомлення;
- створює
AgentTask; - ставить завдання в чергу
agent-tasks.
Маршрут одразу повертає { received: true }; обробка асинхронна, щоб влізти в таймаут відповіді Meta.
Спільний agent-task воркер виконує інʼєкцію профілю, RAG, генерацію, privacy-перевірки, ескалацію персони, обхід матриці довіри та HITL-маршрутизацію для WhatsApp і Telegram.
Вихідний
- Схвалене/автопропущене повідомлення ставиться у чергу
wa-outbound. - Воркер викликає
WhatsAppSender.send(). - Rate limiter (token bucket) чекає на доступну квоту.
- Повідомлення відправляється через
POST /{phoneNumberId}/messagesу Cloud API.
Ендпоінти
| Метод | Шлях | Опис |
|---|---|---|
GET | /api/v1/whatsapp/status | Статус підключення Cloud API |
GET | /api/v1/whatsapp/webhook | Верифікація Meta webhook (hub.challenge) |
POST | /api/v1/whatsapp/webhook | Прийом вхідних повідомлень від Meta |
Форматування повідомлень
Відправник підтримує нативне форматування WhatsApp:
*bold*_italic_~strikethrough~`код`та```code block```
Rate limiting
Token bucket на процес відправника. Налаштовується через WA_RATE_LIMIT_PER_MIN (дефолт: 60 повідомлень/хв).
Зберігання токенів
OAuth access-токени зберігаються в Redis під префіксом ключа <sessionKeyPrefix><phoneNumber>:. Для кожного токена — два ключі:
| Суфікс ключа | Значення |
|---|---|
access_token | Поточна строка access token |
token_expires_at | Unix ms timestamp закінчення дії (порожній рядок, якщо невідомо) |
Токени ротуються проактивно, коли до експірації лишилось менше 7 днів. Щоб скинути збережені токени (наприклад, після revoke) — викличте clearTokenState(redis, keyPrefix) з auth-state.ts.
Telegram
Адаптер Telegram використовує Grammy — Telegram Bot Framework для Node.js.
Архітектура
src/channels/telegram/
├── index.ts # Service factory
├── plugin.ts # Fastify plugin (routes)
├── bot.ts # Grammy bot initialization
├── handler.ts # Transport normalization + AgentTask creation
├── sender.ts # Outbound message formatting
├── queue.ts # BullMQ inbound/outbound workers
├── conversation-repository.ts # Prisma conversation store
└── types.ts # Config and message types
Конфігурація
| Змінна | За замовчуванням | Опис |
|---|---|---|
TG_BOT_TOKEN | — | Telegram bot token від @BotFather |
TG_RATE_LIMIT_PER_MIN | 30 | Макс повідомлень на хвилину |
Налаштування
- Створіть бота через @BotFather у Telegram
- Скопіюйте bot token
- Задайте
TG_BOT_TOKENу.env - Перезапустіть сервер
Поточний плагін запускає бота в режимі long-polling і експонує status-ендпоінт.
Потік повідомлень
Вхідний
- Grammy отримує повідомлення через long-polling
- Повідомлення стає в чергу
tg-inbound(BullMQ) - Воркер:
- шукає/створює User і Conversation за Telegram user ID;
- зберігає вхідне повідомлення;
- створює
AgentTask; - ставить завдання в чергу
agent-tasks.
Далі спільний agent-task воркер вирішує: відправити автоматично, створити HITL-схвалення чи ескалувати до персони.
Вихідний
- Схвалене повідомлення ставиться у чергу
tg-outbound - Воркер форматує під Telegram MarkdownV2 / HTML
- Відправляє через Grammy bot API
- Rate limiter приглушує за потребою
Ендпоінти
| Метод | Шлях | Опис |
|---|---|---|
GET | /api/v1/telegram/status | Статус бота |
Форматування повідомлень
Telegram підтримує:
**bold**_italic_`inline code`- Блоки коду
- HTML-форматування як fallback
Трекінг розмов
Кожен Telegram-користувач трекається за його tg_user_id. Conversation-репозиторій створює записи User і Conversation при першому контакті — аналогічно до WhatsApp-адаптера.