| 02-agent-features |
03 |
messaging |
| whatsapp |
| meta-cloud-api |
| hmac |
| webhook |
| minio |
| normalization |
| business-scoping |
| media |
|
| phase |
provides |
| 01-foundation |
KonstructMessage model, channel gateway, normalize.py, resolve_tenant, check_rate_limit, is_duplicate/mark_processed |
|
|
| WhatsApp Business Cloud API channel adapter (packages/gateway/gateway/channels/whatsapp.py) |
| normalize_whatsapp_event() normalizing Meta Cloud API v20.0 payloads to KonstructMessage |
| MediaAttachment and MediaType models in shared/models/message.py |
| media: list[MediaAttachment] field added to MessageContent |
| verify_whatsapp_signature() HMAC-SHA256 on raw body bytes |
| verify_hub_challenge() for Meta webhook registration handshake |
| is_clearly_off_topic() tier 1 keyword scoping gate |
| build_off_topic_reply() canned redirect message builder |
| send_whatsapp_message() and send_whatsapp_media() outbound delivery |
| Media download from Meta API + MinIO storage with tenant-prefixed keys |
| WhatsApp routes registered in gateway main.py |
| whatsapp_app_secret, whatsapp_verify_token, MinIO settings added to shared/config.py |
|
| 02-agent-features/02-05 — outbound response routing in orchestrator tasks.py must route whatsapp channel through send_whatsapp_message |
| 02-agent-features — any plan touching gateway/normalize.py should import MediaAttachment/MediaType |
|
| added |
patterns |
| boto3 (not yet in pyproject.toml — added inline in media download function, needs uv add) |
| httpx (already in gateway deps — used for Meta API calls) |
|
| Raw body read BEFORE JSON parsing for HMAC verification (prevent tampered-body attack) |
| verify_whatsapp_signature returns raw bytes on success, raises HTTPException(403) on failure |
| verify_hub_challenge returns challenge string on success, raises HTTPException(403) on failure |
| normalize_whatsapp_event: meta-media://{media_id} placeholder URL before actual download |
| Two-tier scoping: keyword gate (no LLM) -> LLM with system prompt scoping |
| Always return 200 OK to Meta regardless of processing errors (Meta retry prevention) |
| thread_id = sender wa_id for WhatsApp (no threading concept in WhatsApp) |
|
|
| created |
modified |
| packages/gateway/gateway/channels/whatsapp.py |
| tests/unit/test_whatsapp_verify.py |
| tests/unit/test_whatsapp_normalize.py |
| tests/unit/test_whatsapp_scoping.py |
|
| packages/shared/shared/models/message.py |
| packages/shared/shared/config.py |
| packages/gateway/gateway/normalize.py |
| packages/gateway/gateway/main.py |
|
|
| HMAC uses hmac.new() (not hmac.HMAC()) for timing-safe signature verification via hmac.compare_digest |
| meta-media://{media_id} placeholder URL set at normalization time; actual download in adapter after tenant resolution |
| thread_id set to sender wa_id — WhatsApp conversation scope is per-phone-number, not thread-based |
| Always return HTTP 200 to Meta webhooks regardless of processing errors to prevent Meta retry storms |
| Tier 1 scoping uses word-level tokenization with set intersection for keyword overlap check |
| MinIO settings added to shared/config.py alongside WhatsApp credentials for use by all services |
| boto3 required for MinIO access (S3-compatible client); needs uv add boto3 in gateway package before prod |
|
| WhatsApp adapter pattern: verify signature on raw bytes -> normalize -> tenant resolve -> rate limit -> dedup -> scope -> media -> dispatch |
| Business-function scoping: tier 1 (keyword) rejects clearly off-topic without LLM; tier 2 (LLM) enforces via system prompt |
| Canned redirect format: '{agent_name} is here to help with {topics}. How can I assist you with one of those?' |
|
|
7min |
2026-03-23 |