WhatsApp Business Agent scaffold
A complete program, not a fragment: it compiles as written. Copy it, rename the
placeholder identifiers to your domain, and run axon check — the compiler will
tell you what your renaming broke. An MCP client can also generate it through the
axon.compose tool by naming the whatsapp domain.
// AXON WhatsApp Business Agent scaffold — webhook-driven conversational
// agent consuming the WA Business API + a persistent per-user memory.
//
// The WA Business policy requires structured message types (text,
// template, interactive) + session windows. This scaffold encodes:
// - typed inbound payload (one type per WA message kind),
// - typed outbound payload (the agent's reply),
// - per-phone-number persistent memory binding,
// - a single axonendpoint at /v1/whatsapp/webhook,
// - shield over PII (the phone-number is PII).
// ── Types ─────────────────────────────────────────────────────────
type WAInboundText {
phone_number: Text
message_id: Text
body: Text
received_at: Text
}
type WAOutboundReply {
reply_to: Text
message_id: Text
body: Text
}
type WebhookRequest { msg: WAInboundText }
// ── Identity + grounding ──────────────────────────────────────────
persona WhatsAppBusinessAgent {
domain: ["customer-support", "conversational-commerce"]
tone: friendly
confidence_threshold: 0.7
cite_sources: false
language: "es"
}
context WAConversation {
memory: persistent
language: "es"
depth: standard
max_tokens: 1024
temperature: 0.5
}
anchor StayInSessionWindow {
require: source_citation
confidence_floor: 0.6
unknown_response: "Disculpa, no entendí. ¿Podrías reformular?"
on_violation: log
}
// ── Shields — phone-number is PII ─────────────────────────────────
shield WhatsAppShield {
scan: [prompt_injection, pii_leak, social_engineering]
// `on_breach:` is the closed-catalog policy
// (deflect|escalate|halt|quarantine|sanitize_and_retry). The
// `redact:` field below names FIELDS to redact when
// sanitize_and_retry fires — the two are distinct concepts.
on_breach: sanitize_and_retry
severity: medium
redact: [phone_number]
compliance: [SOC2]
}
// ── Per-user memory ───────────────────────────────────────────────
memory WAUserMemory {
store: persistent
backend: postgresql
retrieval: exact
}
// ── Flow ──────────────────────────────────────────────────────────
flow HandleWAMessage(msg: WAInboundText) -> FlowEnvelope<WAOutboundReply> {
step Reply {
given: msg
ask: "Reply in the same language as the inbound message; stay inside the WA Business session window (no off-topic, no unsolicited templates)."
output: FlowEnvelope<WAOutboundReply>
}
return Reply.output
}
// ── HTTP boundary ─────────────────────────────────────────────────
axonendpoint WhatsAppWebhookAPI {
method: post
path: "/v1/whatsapp/webhook"
body: WebhookRequest
execute: HandleWAMessage
output: FlowEnvelope<WAOutboundReply>
shield: WhatsAppShield
backend: auto
compliance: [SOC2]
retries: 1
timeout: 15s
requires: ["whatsapp.webhook.handle"]
}