Answer Card multi-channel — render server-side theo type

Agent sinh block {template_id, type, data} → render(id,type,data) server-side → output theo kênh: web=card_json SSE, zalo/fb=message JSON qua tool-exec. Template N-tab. Thiết kế đích (ADR-028 rev3), CHƯA build.

01 / SINH BLOCK (type) 02 / RENDER SERVER-SIDE THEO TYPE 03A / WEB → SSE 03B / ZALO/FB → CHANNEL API final_answer chứa block {template_id, type, data} type = channel đích (agent truyền); data sinh runtime, full context parse block khỏi content card THAY text — không stream final_answer song song (tránh double-render) render(template_id, type, data, allowlist) một entry point cho mọi channel — chọn variant theo type fetch layout variant (template_id, version, type) cache immutable — không SELECT mỗi turn; thiếu tab type → degrade text validate variant + strip allowlist LLM data tự do → strip open_url ngoài allowlist, mọi channel — BẮT BUỘC output theo type (card_json | zalo_json | fb_json | text) web→card_json · zalo→OA JSON · fb→Messenger JSON · text→plain [type=web] card_json qua SSE FE answer-card.tsx render card_json — KHÔNG parse markdown (đã render server) render 8-type component + action postback/open_url (đã strip ngoài allowlist ở server) [type=zalo] oa.send_message(zalo_json) delivery adapter — biết session.channel; OBO token khách POST Zalo OA API / FB Messenger API gửi message JSON đã render — outbound, khách nhận trên app kênh LLM / node sinh block + type runtime agent/workflow :50056 render lib render(id,type,data) version-svc layout N-tab :50082 chat UI web render card_json tool-exec oa.send_message :5002 Zalo / FB channel API Legend request (hot path) return / read auth / policy gate async / stream

Template N-tab (control plane)

  • • một card_template = {web, fb, zalo, text} variant
  • • authoring Studio N-tab, đóng băng cùng Workspace Version
  • • layout immutable per (template_id, version, type)
  • • thiếu tab type → degrade text (không vỡ)

render(id, type, data) — một seam đa kênh

  • • web → card_json → SSE → FE render
  • • zalo → OA JSON → tool-exec oa.send_message → Zalo API
  • • fb → Messenger JSON → channel API
  • • text → plain (fallback kênh không support card)

Xử 5 lỗ mô hình cũ

  • • data runtime (agent sinh) → binding không rỗng
  • • card THAY text → không double-render
  • • adapter chung → chatflow/tool không dead-end
  • • cache layout immutable → không per-turn DB read
  • • strip allowlist server-side mọi channel — bảo mật