S211.1 Unified Rich Messaging Phase1
Documentation for Sessions
S211.1 — Unified Rich Messaging & Alert System Improvements
Session: S211.1 | Date: 2026-03-12 | Branch:
session-211Status: Phase 1 Complete | Next: S211.2 (Phase 2: Personality & Expression)
What We Built (Plain English)
The Big Picture
Vitto — our AI assistant — talks to users across multiple channels: WhatsApp, the web app, Slack, and Discord. Until now, every message Vitto sent was plain text. Whether it was listing options, completing a task, or sending an alert — it was always just a wall of text.
S211.1 changes this. We built a system that lets Vitto send rich, interactive messages — cards with action buttons, selectable lists, carousels, deep links ("Open in GoGrab"), and quick reply chips. The same message looks great on WhatsApp AND on the web — they share the same underlying structure, just rendered differently for each platform.
We also fixed a critical production bug where users were getting flooded with duplicate alert messages on WhatsApp.
Timeline of Changes
1. Escalation Alert Spam Fix (URGENT — shipped first)
The Problem: When a backend service went down (e.g., backend-docs-api), our health monitoring system would send the same alert message 3+ times to WhatsApp, every 30 minutes, indefinitely. Users were getting spammed with identical plain-text walls.
Root Causes Found:
- The system sent one WhatsApp message per alert record instead of grouping by the actual problem
- No memory of past escalations — it re-sent every 30 minutes
- It bypassed all our safety guards (dedup, frequency limits, quiet hours)
- Every user with WhatsApp linked got system alerts, even regular users who can't act on infrastructure issues
What We Fixed:
- Grouping: Multiple alerts for the same issue now produce ONE consolidated message with a count (e.g., "3 Unresolved Critical Alerts — api-health")
- Dedup: Won't re-send the same alert type within 6 hours
- Safety Guards: Now routes through our central notification dispatcher, which enforces dedup, daily frequency caps, and quiet hours
- Role Filtering: Only administrators, developers, and executives receive system escalation alerts — regular users are no longer spammed
Impact: Immediate relief for all WhatsApp-connected users. What was 3+ messages per outage every 30 minutes is now 1 message per root cause, once every 6 hours, only to people who can actually act on it.
2. Rich Message Type System (Foundation)
What: We created a universal vocabulary for rich messages — 8 types that work across any channel:
| Type | What It Looks Like | When Vitto Uses It |
|---|---|---|
| Text | Plain text | Short responses, greetings |
| Quick Reply | 2-3 tappable buttons | Yes/no questions, follow-up options |
| List Picker | Selectable option list | "Choose a module to create" with 3+ options |
| Card | Structured card with title, body, buttons | Task completion summaries |
| Carousel | Horizontal scrollable cards | Browsing templates, comparing options |
| CTA Button | Prominent "Open in GoGrab" link | Deep links after task completion |
| Media | Image, video, audio, document | (Future use) |
| Location | Map pin with address | (Future use) |
Why It Matters: Before this, adding any interactive feature (like a list picker) required separate code for WhatsApp, separate code for web, separate code for Slack — 4x the work per feature. Now, Vitto creates ONE rich message and each channel automatically renders it in its native format.
3. Channel Adapters (WhatsApp + Web)
What: Two "translators" that convert universal rich messages into channel-specific formats:
WhatsApp Adapter: Converts to Twilio Content API templates (list pickers, cards with buttons, carousels). Uses the production WhatsApp Business Account (GOGRAB LLC, verified since 2019, 80 messages/second throughput).
Web Chat Adapter: Converts to interactive Angular components rendered inline in the chat. Uses the existing generative-ui system — the same tech that renders skill previews and alert badges.
Smart Fallback: If a rich message can't be rendered on a channel (e.g., no adapter registered for Slack yet), it automatically falls back to the plain text version. Nothing breaks.
4. Intelligent Response Composer
What: An automatic analyzer that looks at Vitto's response text and decides which rich message type to use. No LLM call needed — it's instant and free.
How It Decides:
- Response lists 3+ numbered options → List Picker (selectable)
- Response ends with "Would you like me to...?" → Quick Reply (Yes/No/More buttons)
- Task completed with a URL path → CTA Button ("Open in GoGrab" deep link)
- Task completed with long summary → Card (structured with action buttons)
- Short response → Plain text (no overhead)
5. Web Chat Rich Components
What: 5 new Angular components that render rich messages in the web chat:
- List Picker — Clickable option groups with descriptions
- Rich Card — Title + subtitle + body + optional image + action buttons
- Carousel — Horizontally scrollable card strip
- CTA Button — Prominent deep link with icon
- Quick Reply Chips — Row of tappable response suggestions
These are registered in the existing generative-ui catalog and render automatically when Vitto's response contains rich content. No changes were needed to the chat message parser.
6. Alert Rich Formatting
What: System alerts (health checks, escalations) are now sent as structured cards with action buttons instead of plain text walls.
Before:
🚨 *ESCALATION: Unresolved Critical Alert*
Alert: api-health
Created: 2026-03-10T19:50:00.347Z
Details: Services unreachable: backend-docs-api
...
After: A structured card with:
- Clear title with severity badge
- Consolidated details
- "Acknowledge" button
- "Mute 1h" button
7. Production Build Fix
What: Fixed a TypeScript type error (module-gen.error → module-gen.failed) in the module generation pipeline that was blocking Railway deployments. This was a pre-existing bug from the S212 budget enforcement code, not from our S211 changes.
By the Numbers
| Metric | Value |
|---|---|
| Commits | 14 |
| New files created | 15 |
| Files modified | 5 |
| New tests | 35 |
| Test suites | 6 |
| All tests passing | Yes |
| Production bugs fixed | 3 |
| Build blockers resolved | 1 |
What's Next (Future Sessions)
Phase 2: Personality & Expression (S211.2)
- Contextual Vitto-branded stickers (WebP reactions)
- Adaptive emoji based on conversation mood (not fixed pools)
- Voice note intelligence (detect when voice is better than text)
- Conversation mood/tone detection
Phase 3: WhatsApp Flows (S211.3)
- Onboarding Flow — Multi-screen welcome for new WhatsApp users
- Module Config Flow — Configure and generate modules entirely from WhatsApp
- Deployment Approval Flow — Review changes and approve deployments from WhatsApp
- Quick Settings Flow — Change app settings (colors, layout) from WhatsApp
Future Enhancements
- Slack/Discord Adapters — Block Kit and Embed conversion for rich messages
- LLM Structured Output — Have the AI directly output rich message JSON instead of heuristic text parsing
- User Reply Routing — Handle when a user taps a list picker selection and route the response correctly
Architecture Overview (For Technical Reference)
Agent Loop Output (plain text)
↓
RichMessageComposerService (heuristic analysis → picks message type)
↓
RichMessage (channel-agnostic)
↓
AdapterRegistryService (resolves channel → adapter)
↓
┌────────────────────┬──────────────────────┐
│ WhatsApp Adapter │ Web Chat Adapter │
│ (Twilio Content │ (generative-ui │
│ API → sends │ JSON blocks → │
│ directly) │ Angular renders) │
└────────────────────┴──────────────────────┘
Key Design Principles:
- Channel parity: Same message looks appropriate on every platform
- Graceful fallback: If rich rendering fails, plain text is always sent
- No parser changes: Web chat already had a generative-ui component system — we just added new components
- Backward compatible: All new service injections use
@Optional()— nothing breaks if services aren't available
Files Changed (Complete List)
New Files (Backend)
engine/rich-messages/rich-message.types.ts— 8 message types + factory helpersengine/rich-messages/rich-message-composer.service.ts— Heuristic type selectorengine/adapters/channel-adapter.interface.ts— Adapter contractengine/adapters/adapter-registry.service.ts— Channel → adapter mappingengine/adapters/whatsapp-channel.adapter.ts— WhatsApp via Twilioengine/adapters/web-chat-channel.adapter.ts— Web via generative-uiengine/__tests__/adapter-registry.spec.ts— 5 testsengine/__tests__/whatsapp-adapter.spec.ts— 6 testsengine/__tests__/web-chat-adapter.spec.ts— 7 testsengine/__tests__/rich-message-composer.spec.ts— 7 testsengine/__tests__/rich-message-integration.spec.ts— 4 testsproactive/__tests__/escalation-grouping.spec.ts— 6 tests
New Files (Frontend)
generative-ui/components/rich-list-picker.component.tsgenerative-ui/components/rich-card.component.tsgenerative-ui/components/rich-carousel.component.tsgenerative-ui/components/rich-cta-button.component.tsgenerative-ui/components/rich-quick-reply.component.ts
Modified Files
engine/engine.module.ts— Registered new servicesengine/channel-processing.service.ts— Wired composer + adaptersgenerative-ui/catalog-seed.ts— Registered 5 new componentsproactive/proactive-monitor.service.ts— Escalation fix + role filterproactive/proactive-dispatcher.service.ts— Rich card formattingmodule-generation/phases/module-gen-phase.executor.ts— SSE type fix