fix(buttons): use empty native_flow name for all regular buttons + fix scope issue

- Changed native_flow name from 'mixed' to '' (empty) for all regular buttons
  (both CTA and quick_reply), matching WhatsApp client traffic analysis
- Only special flows (payment_info, mpm, order_details) get specific names
- Fixed variable scope: moved hasCTA/hasQuickReply/isCTAOnly before if/else block
  to ensure they're accessible for bot node conditional logic
- Removed duplicate CTA_BUTTON_NAMES/allButtonNames declarations

https://claude.ai/code/session_01EK9NpViRCtda1WAvFd8ptR
This commit is contained in:
Claude
2026-02-06 11:42:06 +00:00
parent e9190e01d3
commit a64596202f
+22 -25
View File
@@ -1263,6 +1263,13 @@ export const makeMessagesSocket = (config: SocketConfig) => {
metrics.interactiveMessagesSent.inc({ type: buttonType }) metrics.interactiveMessagesSent.inc({ type: buttonType })
try { try {
// Classify button types for native_flow name and bot node decisions
const CTA_BUTTON_NAMES = new Set(['cta_url', 'cta_copy', 'cta_call'])
const allButtonNames = nativeFlowButtons.map((b: any) => b?.name).filter(Boolean)
const hasCTA = allButtonNames.some((name: string) => CTA_BUTTON_NAMES.has(name))
const hasQuickReply = allButtonNames.some((name: string) => name === 'quick_reply')
const isCTAOnly = hasCTA && !hasQuickReply
// For listMessage (legacy format), use direct <list> tag // For listMessage (legacy format), use direct <list> tag
// This matches pastorini's working implementation // This matches pastorini's working implementation
if (buttonType === 'list') { if (buttonType === 'list') {
@@ -1285,29 +1292,24 @@ export const makeMessagesSocket = (config: SocketConfig) => {
) )
} else { } else {
// Determine the native_flow name based on actual button types // Determine the native_flow name based on actual button types
// WhatsApp Web requires correct name attribute to render buttons: // Based on WhatsApp client traffic analysis (see getButtonArgs),
// - CTA-only buttons (cta_url, cta_copy, cta_call): name should be empty '' // the default name for regular native_flow buttons should be '' (empty)
// - quick_reply-only buttons: name should be 'quick_reply' // Only special flows (payment, mpm, order) need specific names
// - mixed (CTA + quick_reply): name should be 'mixed' // Using '' for all regular buttons (CTA and quick_reply) ensures
const CTA_BUTTON_NAMES = new Set(['cta_url', 'cta_copy', 'cta_call']) // maximum compatibility with WhatsApp Web
const buttonNames = nativeFlowButtons.map((b: any) => b?.name).filter(Boolean) const SPECIAL_FLOW_NAMES: Record<string, string> = {
const hasCTA = buttonNames.some((name: string) => CTA_BUTTON_NAMES.has(name)) 'review_and_pay': 'payment_info',
const hasQuickReply = buttonNames.some((name: string) => name === 'quick_reply') 'payment_info': 'payment_info',
'mpm': 'mpm',
let nativeFlowName: string 'review_order': 'order_details'
if (hasCTA && !hasQuickReply) {
// Pure CTA buttons - WhatsApp Web needs empty name for CTA rendering
nativeFlowName = ''
} else if (hasQuickReply && !hasCTA) {
// Pure quick_reply buttons
nativeFlowName = 'quick_reply'
} else {
// Mixed CTA + quick_reply or other combinations
nativeFlowName = 'mixed'
} }
const firstButtonName = allButtonNames[0] || ''
// Check if this is a special flow type, otherwise use '' for Web compatibility
const nativeFlowName = SPECIAL_FLOW_NAMES[firstButtonName] || ''
logger.info( logger.info(
{ msgId, buttonNames, hasCTA, hasQuickReply, nativeFlowName }, { msgId, buttonNames: allButtonNames, hasCTA, hasQuickReply, isCTAOnly, nativeFlowName, firstButtonName },
'[EXPERIMENTAL] Determined native_flow name based on button types' '[EXPERIMENTAL] Determined native_flow name based on button types'
) )
@@ -1349,11 +1351,6 @@ export const makeMessagesSocket = (config: SocketConfig) => {
destinationJid?.endsWith('@c.us') destinationJid?.endsWith('@c.us')
) && !isJidBot(destinationJid) ) && !isJidBot(destinationJid)
// Detect if message contains only CTA buttons (no quick_reply)
const ctaButtonNames = new Set(['cta_url', 'cta_copy', 'cta_call'])
const allButtonNames = nativeFlowButtons.map((b: any) => b?.name).filter(Boolean)
const isCTAOnly = allButtonNames.length > 0 && allButtonNames.every((name: string) => ctaButtonNames.has(name))
if (isPrivateUserChat && !isCarousel && !isCatalog && buttonType !== 'list' && !isCTAOnly) { if (isPrivateUserChat && !isCarousel && !isCatalog && buttonType !== 'list' && !isCTAOnly) {
;(stanza.content as BinaryNode[]).push({ ;(stanza.content as BinaryNode[]).push({
tag: 'bot', tag: 'bot',