Doc Status: Design target with current implementation notes.
/llm/manychat already exists and sends asynchronous final answers through ManyChat sendContent. The natural typing-indicator worker is the next implementation step and depends on a confirmed ManyChat typing-indicator API surface.Why This Matters
Guests who message House of Legends on Instagram, Messenger, or WhatsApp expect a human-paced chat experience. The integration must acknowledge ManyChat immediately, prepare the real answer in the background, and keep the conversation feeling alive while the AI agent checks live show, pricing, and availability data. ManyChat remains the social messaging layer. Mastra owns the AI turn, and Hono remains the source of truth for public catalog facts, availability, pricing, policies, booking links, and inquiry submission.Target Experience
When ManyChat sends a guest message to House of Legends:Receive the ManyChat request
ManyChat calls
POST https://houseoflegends.vn/llm/manychat with the guest message, channel, locale, and contact data.Acknowledge immediately
Mastra validates the shared webhook token, extracts the message and subscriber ID, then returns a fast ManyChat Dynamic Block response so ManyChat does not wait on the LLM.
Start the background worker
The Worker uses
executionContext.waitUntil(...) to continue after the HTTP response has been returned to ManyChat.Run two background tasks together
The background worker starts response generation and a typing-indicator loop at the same time.
Runtime Flow
Current Implementation
The current code already implements the main async path:| Concern | Current behavior | File |
|---|---|---|
| Route | POST /llm/manychat mounted in the Mastra Worker | apps/mastra/src/worker.ts |
| Auth | Requires x-hol-manychat-token or Authorization: Bearer ... | apps/mastra/src/manychat/manychat-route.ts |
| Request parsing | Accepts last_input_text, text, message, query, or contact.last_input_text | apps/mastra/src/manychat/manychat-route.ts |
| Channels | Accepts facebook, messenger alias, instagram, whatsapp, and telegram | apps/mastra/src/manychat/manychat-route.ts |
| Async ack | Returns a ManyChat Dynamic Block version: "v2" acknowledgement when a subscriber ID is available | apps/mastra/src/manychat/manychat-route.ts |
| Final answer | Calls the Mastra customer-support router, audits internal links, then calls ManyChat sendContent | apps/mastra/src/manychat/manychat-route.ts |
| Data source | Uses @hol/client and Hono assistant-safe endpoints, not direct database access | apps/mastra/src/mastra/tools/catalog-tools.ts |
Background Worker Contract
The ideal background worker should be shaped like this:Typing Indicator Behavior
The typing loop should feel natural without becoming noisy:| Rule | Requirement |
|---|---|
| Start quickly | Turn typing on shortly after the ack, unless the final answer is already ready. |
| Random cadence | Alternate typing on and off with jittered delays so it does not look robotic. |
| Low call volume | Keep the interval conservative to avoid ManyChat Public API limits and channel throttling. |
| Final cleanup | Always send a final typing-off call in finally. |
| Failure isolation | Typing API failures should be logged and ignored. They must never block response generation or final sendContent. |
| Channel awareness | Only run typing where ManyChat confirms support for the channel. |
| Setting | Value |
|---|---|
| Initial delay | 400-900 ms |
| Typing-on window | 2.2-4.8 seconds |
| Typing-off pause | 600-1,800 ms |
| Maximum loop duration | 55 seconds |
| Maximum failures before silence | 3 |
manychat-route.ts or a small ManyChat helper module, not scattered through the route.
ManyChat API Dependency
The current public ManyChat Swagger for the Page API exposes the sending namespace with:POST /fb/sending/sendContentPOST /fb/sending/sendContentByUserRefPOST /fb/sending/sendFlow
https://api.manychat.com/swagger/compileJson?type=Page_API. The generation script runs fern api update into an ignored temporary path during generation; do not keep a checked-in local copy of the vendor spec.
It does not show a public typing-indicator endpoint. Before implementing the loop, confirm one of these with the ManyChat account/API documentation:
- Preferred
- Fallback
ManyChat provides an official typing action endpoint. Implement a small typed helper such as
sendManyChatTypingIndicator and keep the endpoint path/body in one place.Do not call Meta Graph API directly from Mastra for these channels unless the ownership model changes. ManyChat owns platform delivery, opt-in state, channel limits, and handoff routing.
Request Contract
ManyChat should send:subscriber_ididuser_idcontact.idcontact.user_id
sendContent; the route falls back to synchronous generation.
Environment Variables
- Required today
- Typing loop
Operational Rules
- Do not hardcode show names, dates, prices, capacity, booking URLs, or policy in ManyChat flows.
- Do not send secrets through ManyChat message text, custom fields, or public replies.
- Do not send payment data, private reservation notes, or internal operator data to ManyChat.
- Keep all House of Legends links absolute and locale-prefixed.
- If the agent needs richer live facts, improve Hono assistant-safe endpoints first, then consume them through
@hol/client. - Typing simulation must be best-effort only. A typing failure is a cosmetic failure, not a customer-support failure.
Verification
Run a ManyChat external request test
Confirm the request returns HTTP 200 with
version: "v2" and the immediate acknowledgement message.Confirm async final delivery
Ask a live-data question such as “What shows are available this weekend?” and confirm the final answer arrives through ManyChat after the background agent turn finishes.
Verify typing once implemented
Confirm typing starts after the ack, toggles naturally while generation runs, and turns off after the final answer is sent. Repeat on every enabled channel.
