+
    kHàjÕþ  ã                  ó¢  a€ 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIHt ^ RIHtHtHt  ^ RIHt Rt ^ RItRt^ R	IHtH t  ^ R
I!H"t" ^ RI#H$t$ ^ RI%H&t&H't'H(t(H)t) ^ RI*H+t+ ^ RI,H-t- ^ RI.H/t/H0t0 ^ RI1H2t2H3t3 ^ RI4H5t6 ^ RI7H8t8 ^ RI9H:t: ^ RI;H<t< ]
Pz                  ! ]>4      t?Rt@RtARtBRtCRtDRStERtFRtGRRTRRURRURRWRRV/tHRR RR!RR"RR#RR$/tI]P”                  ! R%4      tKR&R'R(R'R)R'R*R+R,R+R R-/tLR.]MR/&   0 RXmtN0 RYmtO0 RZmtPRVtQR1]0P¤                  R]0P¦                  R]0P¨                  R]0Pª                  R0]0Pª                  R]0P¬                  R]0P¦                  R2]0P¤                  R3]0P¤                  R4]0P¤                  R5]0P¤                  /tWR[tXR6 R7 ltYR1R8 R2R9 R3R: /]N U u/ uF	  q V 3R; lbK  	  up CtZR< R= lt[R> R? lt\R@ RA lt]RB RC lt^RD RE lt_]! ]<! RFRG4      4      t`RH RI lta ! RJ RK]2]&4      tbRL RM ltcRN RO ltdRPteRQ RR ltfR#   ] d	    RtRt ELÚi ; i  ] d	    RtRt ELåi ; iu up i )\uV  WhatsApp Cloud API adapter â€” official Meta WhatsApp Business Platform (Graph API +
aiohttp webhook). Complements the Baileys bridge plugin; both share gating / mention /
formatting behavior via ``WhatsAppBehaviorMixin``.

Required env: WHATSAPP_CLOUD_PHONE_NUMBER_ID, WHATSAPP_CLOUD_ACCESS_TOKEN. Optional:
WHATSAPP_CLOUD_APP_ID, _APP_SECRET (HMAC key for X-Hub-Signature-256),
_WABA_ID (when set, inbound webhooks must match it),
_VERIFY_TOKEN (hub.verify_token), _WEBHOOK_HOST (unset â†’ dual-stack all interfaces),
_WEBHOOK_PORT (8090), _WEBHOOK_PATH (/whatsapp/webhook), _API_VERSION (v20.0).)ÚannotationsN)ÚOrderedDict)ÚPath)ÚAnyÚDictÚOptional)ÚwebTF)ÚPlatformÚPlatformConfig)Úconfig_connected_extra)Út)ÚBasePlatformAdapterÚExecApprovalPromptÚ
SendResultÚtranscode_to_ogg_opus©Úea_header_text)Úbounded_put)ÚMessageEventÚMessageType)ÚWhatsAppBehaviorMixinÚ_get_wsecret)ÚOPTIN_TRUTHY)Úext_for_mime)Úrich_sent_store)Úget_hermes_dirzv20.0iš  z/whatsapp/webhookzhttps://graph.facebook.comiˆ  iè  ÚimageÚvideoÚaudioÚdocumentÚstickerz
image/jpegz	video/mp4ú
audio/mpegúapplication/octet-streamz
image/webpÚffmpegz	audio/oggú.oggzaudio/x-opus+oggz
audio/opusz	audio/mp4z.m4azaudio/x-m4az.jpgúdict[str, str]Ú"_WHATSAPP_MIME_EXTENSION_OVERRIDESÚvoiceÚtextÚbuttonÚinteractiveÚlocationÚcontactsc               ó    € V ^8„  d   QhRRRR/# )é   Úraw_messageúdict[str, Any]Úreturn© )Úformats   "ÚM/home/ubuntu/.hermes/hermes-agent/plugins/platforms/whatsapp_cloud/adapter.pyÚ__annotate__r5   l   s   € ÷ Fñ F Nð F°~ñ Fó    c                ó    € V P                  R4      ;'       g    / pVP                  R4      ;'       g    VP                  R4      ;'       g    / # )zR``button_reply`` (type=button) or ``list_reply`` (type=list); both carry id+title.r*   Úbutton_replyÚ
list_reply©Úget)r/   Úinters   & r4   Ú_interactive_innerr=   l   s@   € à�O‰O˜MÓ*×0Ð0¨b€EØ�9‰9�^Ó$×EÐE¨¯	©	°,Ó(?×EÐEÀ2ÐEr6   c                óV   € V P                  R 4      ;'       g    / P                  R4      # )r(   Úbodyr:   ©Úms   &r4   Ú<lambda>rB   t   s   € �q—u‘u˜V“}×*Ð*¨×/Ñ/°Ô7r6   c                óV   € V P                  R 4      ;'       g    / P                  R4      # )r)   r(   r:   r@   s   &r4   rB   rB   u   s   € ˜Ÿ™˜x›×.Ð.¨B×3Ñ3°FÔ;r6   c                ó6   € \        V 4      P                  R 4      # )Útitle)r=   r;   r@   s   &r4   rB   rB   v   s   € Ô/°Ó2×6Ñ6°wÔ?r6   c                óV   € V P                  V4      ;'       g    / P                  R 4      # )Úcaptionr:   )rA   Úks   &&r4   rB   rB   w   s   €  §¡ q£§ ¨R× 4Ñ 4°YÔ ?r6   c               ó$   € V ^8„  d   QhRRRRRR/# )r.   Úrequestr   Ú	max_bytesÚintr1   Úbytesr2   )r3   s   "r4   r5   r5   {   s!   € ÷ ñ ¨cð ¸cð Àeñ r6   c              ƒ  óú   "  €  V P                   P                  V^,           4      G Rj  x€L
 p\        V4      V8”  d   \        R4      hV#  L!  \        P                   d   pTP                  p Rp?LERp?ii ; i5i)z8Read at most ``max_bytes`` from an aiohttp request body.Nzpayload too large)ÚcontentÚreadexactlyÚasyncioÚIncompleteReadErrorÚpartialÚlenÚ
ValueError)rJ   rK   r?   Úexcs   &&  r4   Ú_read_limited_request_bodyrW   {   sh   é € ðØ—_‘_×0Ñ0°¸QµÓ?×?ˆô ˆ4ƒy�9ÔÜÐ,Ó-Ð-Ø€Kñ @øÜ×&Ñ&ô Ø�{‰{�ûðüs=   ‚A;„%A ©AªA ®A;ÁA ÁA8Á"A3Á.A;Á3A8Á8A;c               ó    € V ^8„  d   QhRRRR/# )r.   ÚmimeÚstrr1   úOptional[str]r2   )r3   s   "r4   r5   r5   †   s   € ÷ Uñ U˜ð U ñ Ur6   c                ó>   € V '       d   \        V \        RRRR7      # R# )ug   Mime â†’ on-disk extension: WhatsApp overrides â†’ mimetypes â†’ None (never the shared default table).FTN)Ú	overridesÚuse_defaultsÚuse_mimetypesÚfallback)r   r&   )rY   s   &r4   Ú_ext_for_mimera   †   s6   € ÷ GKŒ<˜Ô(JÐY^Ðnrð  ~Bô  Cð  Uð  QUð  Ur6   c               ó   € V ^8„  d   QhRR/# ©r.   r1   Úboolr2   )r3   s   "r4   r5   r5   ‹   s   € ÷ rñ r 4ñ rr6   c                 óˆ   € \        \        R RR7      ;'       g    R4      P                  4       P                  4       \        9   # )ÚWHATSAPP_CLOUD_ALLOW_ALL_USERSÚ ©Údefault)rZ   r   ÚstripÚlowerÚ_OPTIN_TRUTHYr2   r6   r4   Ú_cloud_allow_all_opted_inrm   ‹   s5   € ÜŒ|Ð<ÀbÔI×OÐOÈRÓP×VÑVÓX×^Ñ^Ó`ÔdqÑqÐqr6   c               ó    € V ^8„  d   QhRRRR/# )r.   ÚmetadataúOptional[dict[str, Any]]r1   r[   r2   )r3   s   "r4   r5   r5   �   s   € ÷ 7ñ 7Ð5ð 7¸-ñ 7r6   c                ó8   € T ;'       g    / P                  R 4      # )Úreply_to_message_idr:   )ro   s   &r4   Ú_reply_to_fromrs   �   s   € Ø�NˆN˜×ÑÐ 5Ó6Ð6r6   c               ó$   € V ^8„  d   QhRRRRRR/# )r.   ÚnamerZ   Úunavailable_logr1   r   r2   )r3   s   "r4   r5   r5   “   s!   € ÷ ñ ˜3ð °ð ¸ñ r6   c                ó~   €  \         P                  ! V 4      #   \         d    \        P	                  T4        R# i ; i)zbLazy-import a resolver module (tools.* may be absent in slim installs); None + warning if missing.N)Ú	importlibÚimport_moduleÚImportErrorÚloggerÚwarning)ru   rv   s   &&r4   Ú_optional_moduler}   “   s6   € ðÜ×&Ò& tÓ,Ð,øÜô Ü�‰�Ô'Úðús   ‚ ˜ <»<zplatforms/whatsapp_cloud/mediazwhatsapp_cloud/mediac               ó   € V ^8„  d   QhRR/# rc   r2   )r3   s   "r4   r5   r5       s   € ÷ 1ñ 1¨4ñ 1r6   c                 ó*   € \         ;'       d    \        # )uC   aiohttp (webhook server) + httpx (Graph API) â€” both default deps.)ÚAIOHTTP_AVAILABLEÚHTTPX_AVAILABLEr2   r6   r4   Ú!check_whatsapp_cloud_requirementsr‚       s   € ä×0Ð0¤Ð0r6   c            
      óÔ  a € ] tR t^¥t$ RtRtR]R&   RtR V 3R llt]	R R l4       t
R	 R
 ltRR/R R lltR R lt]	R R l4       tR V 3R lltR R ltR V 3R lltRR/R R lltR R lt]	R R l4       tR Rƒ/R! R" lltR# R$ lt]	R% R& l4       tR„R( R) lltR…R* R+ lltR, R- lt]	R†R. R/ ll4       t]	R‡R0 R1 ll4       t]	R2 R3 l4       t]R4 R5 l4       tR…R6 R7 llt ]!R8 R9 l4       t"R:t#R;t$R< R= lt%R…R> R? llt&R@ RA lt'R…RB RC llt(RDR'RER'RFR'RGR'RHR'/RI RJ llt)RFR'RGR'RHR'RKR'/RL RM llt*R„RN RO llt+R„RP RQ llt,R„RR RS llt-RˆRT RU llt.R„RV RW llt/RX RY lt0RZ R[ lt1R\R'/R] R^ llt2R_ R` lt3Ra Rb lt4Rc Rd lt5Re Rf lt6Rg Rh lt7Ri Rj lt8Rk Rl lt9Rm Rn lt:Ro Rp lt;]	R‰Rq Rr ll4       t<Rs Rt lt=Ru Rv lt>Rw Rx lt?Ry]=Rz]>R{]?/t@R| R} ltA]	R~ R l4       tBR€ R� ltCR‚tDV ;tE# )ŠÚWhatsAppCloudAdapterz Outbound: Graph ``/<api_version>/<phone_id>/messages``; inbound: aiohttp webhook
server. The mixin comes first so its ``format_message`` overrides the base one.Trd   Úserves_profile_prefixc               ó   € V ^8„  d   QhRR/# )r.   Úconfigr
   r2   )r3   s   "r4   r5   Ú!WhatsAppCloudAdapter.__annotate__­   s   € ÷ 00ñ 00˜~ñ 00r6   c                	ó¸  <a€ \         SV `  V\        P                  4       VP                  ;'       g    / oV3R  lR 4       w  V n        V n        V n        V n        V n	        V n
        \        SP                  R4      ;'       g    \        ;'       g    R4      ;'       g    RV n        \        SP                  R\         4      4      V n        V P%                  SP                  R\&        4      4      V n        V P%                  SP                  RR4      4      V n        \        SP                  R\,        4      4      V n        SP                  R	4      V n        V P3                  SR\4        4      pV P7                  V P9                  V4      4      V n        V P:                  '       d   \=        4       '       g   R
MRp\        SP                  R4      ;'       g)    \5        R4      ;'       g    \5        R4      ;'       g    T4      P?                  4       PA                  4       V n!        \        SP                  R4      ;'       g+    \5        R4      ;'       g    \5        RRR7      ;'       g    R4      P?                  4       PA                  4       V n"        V PG                  SRR\4        4      w  rEV P7                  V P9                  V4      4      V n$        V PK                  4       V n&        \O        4       V n(        ^ ;V n)        ;V n*        V n+        RV n,        \O        4       V n-        \O        4       V n.        \O        4       V n/        \O        4       V n0        R;V n1        V n2        R# )c              3  óˆ   <"  € T F7  p\        SP                  V4      ;'       g    R 4      P                  4       x € K9  	  R# 5i©rg   N)rZ   r;   rj   )Ú.0ÚkeyÚextras   & €r4   Ú	<genexpr>Ú0WhatsAppCloudAdapter.__init__.<locals>.<genexpr>±   s:   øé € ð x
ám�ô �—	‘	˜#“×$Ð$ "Ó%×+Ñ+×-Ð-Ûmùs
   ƒ!A¥AÚwebhook_hostrg   NÚwebhook_portÚwebhook_pathÚhealth_pathz/healthÚapi_versionÚreply_prefixÚ	allowlistÚopenÚ	dm_policyÚWHATSAPP_CLOUD_DM_POLICYÚWHATSAPP_DM_POLICYÚgroup_policyÚWHATSAPP_CLOUD_GROUP_POLICYÚWHATSAPP_GROUP_POLICYrh   F)Úphone_number_idÚaccess_tokenÚapp_idÚ
app_secretÚwaba_idÚverify_token)ÚWHATSAPP_CLOUD_ALLOW_FROMÚWHATSAPP_CLOUD_ALLOWED_USERS)Úgroup_allow_fromÚgroupAllowFrom)ÚWHATSAPP_CLOUD_GROUP_ALLOW_FROM)3ÚsuperÚ__init__r	   ÚWHATSAPP_CLOUDrŽ   Ú_phone_number_idÚ_access_tokenÚ_app_idÚ_app_secretÚ_waba_idÚ_verify_tokenrZ   r;   ÚDEFAULT_WEBHOOK_HOSTÚ_webhook_hostrL   ÚDEFAULT_WEBHOOK_PORTÚ_webhook_portÚ_normalize_pathÚDEFAULT_WEBHOOK_PATHÚ_webhook_pathÚ_health_pathÚDEFAULT_API_VERSIONÚ_api_versionÚ_reply_prefixÚ_select_dm_allowlistr   Ú_normalize_allow_idsÚ_coerce_allow_listÚ_allow_fromrm   rj   rk   Ú
_dm_policyÚ_group_policyÚ_select_allowlistÚ_group_allow_fromÚ_compile_mention_patternsÚ_mention_patternsr   Ú_seen_wamidsÚ_duplicate_countÚ_accepted_countÚ_rejected_signature_countÚ_warned_no_ffmpegÚ_last_inbound_wamid_by_chatÚ_clarify_stateÚ_exec_approval_stateÚ_slash_confirm_stateÚ_runnerÚ_http_client)Úselfr‡   Ú	allow_rawÚdefault_dm_policyÚ_Ú
raw_groupsrŽ   Ú	__class__s   &&    @€r4   r«   ÚWhatsAppCloudAdapter.__init__­   sì  ù€ Ü‰Ñ˜¤×!8Ñ!8Ô9Ø—‘×"Ð" ˆôx
ámóx
ÑtˆÔ˜tÔ1°4´<ÀÔAQÐSWÔS`ÐbfÔbtô
 -0°·	±	¸.Ó0I×0gÐ0gÔMa×0gÐ0gÐegÓ,h×,pÐ,pÐlpˆÔÜ"% e§i¡i°Ô@TÓ&UÓ"VˆÔØ"&×"6Ñ"6°u·y±yÀÔQeÓ7fÓ"gˆÔØ!%×!5Ñ!5°e·i±iÀÈyÓ6YÓ!ZˆÔÜ!$ U§Y¡Y¨}Ô>QÓ%RÓ!SˆÔð -2¯I©I°nÓ,EˆÔØ×-Ñ-¨eÐ5rô  uAó  Bˆ	Ø%)×%>Ñ%>¸t×?VÑ?VÐW`Ó?aÓ%bˆÔð ,0×+;×+;Ð+;ÔD]×D_ÒD_™KÐekÐÜ"Ø�I‰I�kÓ"÷ Gð G¤lÐ3MÓ&N÷ Gð GÜÐ0Ó1÷Gð GØ5Fó 
÷ ‰%‹'—%‘%“'ð 	Œô #&Ø�I‰I�nÓ%÷ Oð O¬Ð6SÓ)T÷ Oð OÜÐ3¸VÔD÷Oð OØHNó#
÷ ‰%‹'—%‘%“'ð 	Ôð ×.Ñ.ØÐ9Ð;_Ôamóo‰ˆà+/×+DÑ+DÀT×E\ÑE\Ð]gÓEhÓ+iˆÔØ!%×!?Ñ!?Ó!AˆÔä4?³MˆÔØXYÐYˆÔÐY Ô 4°tÔ7UØ',ˆÔô CNÃ-ˆÔ(ô 6A³]ˆÔÜ;F»=ˆÔ!Ü;F»=ˆÔ!Ø+/Ð/ˆŒ�tÖ(r6   c               ó    € V ^8„  d   QhRRRR/# )r.   Úpathr   r1   rZ   r2   )r3   s   "r4   r5   rˆ   á   s   € ÷ 9ñ 9˜cð 9 cñ 9r6   c                	ó˜   € \        T ;'       g    R 4      P                  4       ;'       g    RpVP                  R4      '       d   V# RV 2# )rg   Ú/)rZ   rj   Ú
startswith)rÛ   Úraws   & r4   r·   Ú$WhatsAppCloudAdapter._normalize_pathà   sA   € ä�$—*�*˜"‹o×#Ñ#Ó%×,Ð,¨ˆØ—n‘n S×)Ò)ˆsÐ8°°3°%¨yÐ8r6   c               ó    € V ^8„  d   QhRRRR/# )r.   rÛ   rZ   r1   r2   )r3   s   "r4   r5   rˆ   å   s   € ÷ hñ h˜sð h sñ hr6   c           	     ój   € \          RV P                   RV P                   RVP                  R4       2# )z<Build a Graph API URL for this adapter's phone-number scope.rÝ   )ÚGRAPH_API_BASEr¼   r­   Úremoveprefix)rÓ   rÛ   s   &&r4   Ú
_graph_urlÚWhatsAppCloudAdapter._graph_urlå   s;   € ä Ð!  4×#4Ñ#4Ð"5°Q°t×7LÑ7LÐ6MÈQÈt×O`ÑO`ÐadÓOeÐNfÐgÐgr6   Ú	json_bodyc               ó    € V ^8„  d   QhRRRR/# )r.   rç   rd   r1   r%   r2   )r3   s   "r4   r5   rˆ   é   s   € ÷ Yñ Y¨$ð Y¸.ñ Yr6   c               	óH   € R RV P                    2/pV'       d	   / VCRR/C# T# )ÚAuthorizationzBearer zContent-Typezapplication/json)r®   )rÓ   rç   Úheaderss   &$ r4   Ú_auth_headersÚ"WhatsAppCloudAdapter._auth_headersé   s6   € Ø" g¨d×.@Ñ.@Ð-AÐ$BÐCˆßBKÐ>�'Ð>˜>Ð+=Ñ>ÐXÐQXÐXr6   c               ó   € V ^8„  d   QhRR/# ©r.   r1   rZ   r2   )r3   s   "r4   r5   rˆ   í   s   € ÷ añ a¨ñ ar6   c                óZ   € V P                   e   V P                   P                  RR4      # R# )uR   Cloud API has no self-chat concept (a Baileys-only setting) â€” no default prefix.z\nÚ
rg   )r½   Úreplace©rÓ   s   &r4   Ú_effective_reply_prefixÚ,WhatsAppCloudAdapter._effective_reply_prefixí   s,   € à:>×:LÑ:LÒ:Xˆt×!Ñ!×)Ñ)¨%°Ó6Ð`Ð^`Ð`r6   c               ó    € V ^8„  d   QhRRRR/# )r.   Úidszset[str]r1   r2   )r3   s   "r4   r5   rˆ   ò   s   € ÷ Uñ U (ð U¨xñ Ur6   c                óž   € V  Uu0 uF<  p\         P                  ! RRVP                  R^4      ^ ,          4      ;'       g    TkK>  	  up# u upi )z_Normalize allowlist entries to bare wa_id (digits): strip ``@...`` JID suffixes and non-digits.ú\Drg   Ú@)ÚreÚsubÚsplit)r÷   Úentrys   & r4   r¿   Ú)WhatsAppCloudAdapter._normalize_allow_idsñ   sH   € ñ QTÓTÑPSÀu”—’�u˜b %§+¡+¨c°1Ó"5°aÕ"8Ó9×BÐB¸UÒBÑPSÑTÐTùÒTs   …:A
Á A
c               ó    € V ^8„  d   QhRRRR/# )r.   ÚtargetrZ   r1   rd   r2   )r3   s   "r4   r5   rˆ   ö   s   € ÷ eñ e¨cð e°dñ er6   c                ó  <€ \        T;'       g    R4      p\        P                  ! RR\        V4      P	                  R^4      ^ ,          4      ;'       g    TpW0P                  V4      9   ;'       g    \        SV `  W4      # )z±Bare-wa_id membership first (Cloud senders are digits), then the shared WhatsApp matcher
so ``*`` and phone/LID aliases keep working for DM intake and groups as they always did.rù   rg   rú   r2   )Úsetrû   rü   rZ   rý   r¿   rª   Ú_entry_matches)rÓ   Úentriesr  ÚbarerØ   s   &&& €r4   r  Ú#WhatsAppCloudAdapter._entry_matchesö   sl   ø€ ô �g—m�m Ó$ˆÜ�vŠv�e˜R¤ V£×!2Ñ!2°3¸Ó!:¸1Õ!=Ó>×HÐHÀ&ˆØ×0Ñ0°Ó9Ñ9×dÐd¼U¹WÑ=SÐT[Ó=dÐdr6   c               ó$   € V ^8„  d   QhRRRRRR/# )r.   Úentry_idr   ro   r1   rd   r2   )r3   s   "r4   r5   rˆ   ý   s!   € ÷ 
ñ 
°#ð 
Àð 
Èñ 
r6   c                óZ  € \        V\        4      '       d   TM/ p\        VP                  R4      ;'       g    R4      P	                  4       p\        T;'       g    R4      P	                  4       pW0P
                  8H  ;'       d(    V P                  '       * ;'       g    W@P                  8H  # )zDBind a signed callback to this adapter's configured Meta identities.rŸ   rg   )Ú
isinstanceÚdictrZ   r;   rj   r­   r±   )rÓ   r	  ro   Úincoming_phone_number_idÚincoming_waba_ids   &&&  r4   Ú_webhook_identity_matchesÚ.WhatsAppCloudAdapter._webhook_identity_matchesý   sŒ   € ä)¨(´D×9Ò9‘8¸rˆÜ#& x§|¡|Ð4EÓ'F×'LÐ'LÈ"Ó#M×#SÑ#SÓ#UÐ Ü˜xŸ~˜~¨2Ó.×4Ñ4Ó6Ðà$×(=Ñ(=Ñ=÷ Ið IØ—]‘]Ô"×GÐGÐ&6¿-¹-Ñ&Gð	
r6   c               ó   € V ^8„  d   QhRR/# )r.   r1   ztuple[str, ...]r2   )r3   s   "r4   r5   rˆ     s   € ÷ Sñ S oñ Sr6   c                ó*   <€ . \         SV `  4       ORN5# )z@Also honor the documented WHATSAPP_CLOUD_ALLOW_ALL_USERS opt-in.rf   )rª   Ú_allow_all_env_names)rÓ   rØ   s   &€r4   r  Ú)WhatsAppCloudAdapter._allow_all_env_names  s   ø€ àR”‘Ñ-Ó/ÐRÐ1QÑRÐRr6   Úis_reconnectFc               ó    € V ^8„  d   QhRRRR/# )r.   r  rd   r1   r2   )r3   s   "r4   r5   rˆ     s   € ÷ &ñ &¨Tð &¸dñ &r6   c             ƒ  	ór  "  € \        4       R R3V P                  ;'       d    V P                  RR33 F$  w  r#pV'       d   K  V P                  W4RR7        R# 	  ^ RIHp \        P                  ! RV! 4       R7      V n        \        P                  ! \        R	7      pVP                  P                  V P                  V P                  4       VP                  P                  V P                   V P"                  4       VP                  P%                  V P                   V P&                  4       ^ R
IHp V! WV P,                  V P.                  V P                   4      G Rj  x€L
 V n        V P3                  4        V P0                  eM   \4        P7                  RV P,                  V P.                  V P                   V P8                  V P                  4       V P:                  '       g   \4        P=                  R4       V P>                  '       g   \4        P=                  R4       V PA                  R4       R#  LÔ5i)Úwhatsapp_cloud_deps_missinguM   aiohttp and httpx are required for whatsapp_cloud â€” reinstall hermes-agent.Úwhatsapp_cloud_unconfiguredzLWHATSAPP_CLOUD_PHONE_NUMBER_ID and WHATSAPP_CLOUD_ACCESS_TOKEN are required.F)Ú	retryable)Úplatform_httpx_limitsg      >@)ÚtimeoutÚlimits)Úclient_max_size)Úbind_listenerNz=[whatsapp_cloud] Listening on %s:%d%s (Graph %s, phone_id=%s)uq   [whatsapp_cloud] WHATSAPP_CLOUD_VERIFY_TOKEN is not set â€” the GET subscription handshake will fail until it is.u¡   [whatsapp_cloud] WHATSAPP_CLOUD_APP_SECRET is not set â€” incoming webhook POSTs will be refused with 503. Set the app secret to enable inbound message delivery.T)!r‚   r­   r®   Ú_set_fatal_errorÚ%gateway.platforms._http_client_limitsr  ÚhttpxÚAsyncClientrÒ   r   ÚApplicationÚWEBHOOK_MAX_BODY_BYTESÚrouterÚadd_getrº   Ú_handle_healthr¹   Ú_handle_verifyÚadd_postÚ_handle_webhookÚ gateway.platforms.shared_ingressr  r´   r¶   rÑ   Ú_mark_connectedr{   Úinfor¼   r²   r|   r°   Ú_wire_plugin_handlers)rÓ   r  ÚokÚcodeÚmessager  Úappr  s   &$      r4   ÚconnectÚWhatsAppCloudAdapter.connect  sÊ  é € ä.Ó0Ð2OØ\ð^à×"Ñ"×9Ð9 t×'9Ñ'9Ð;XØ[ð]ó"
ÑˆB�g÷ ‘2Ø×%Ñ% d¸uÐ%ÔEÚñ"
õ 	PÜ!×-Ò-°dÑCXÓCZÔ[ˆÔô �oŠoÔ.DÔEˆØ�
‰
×Ñ˜4×,Ñ,¨d×.AÑ.AÔBØ�
‰
×Ñ˜4×-Ñ-¨t×/BÑ/BÔCØ�
‰
×Ñ˜D×.Ñ.°×0DÑ0DÔEåBÙ*¨4°d×6HÑ6HÈ$×J\ÑJ\Ð^b×^pÑ^pÓq×qˆŒØ×ÑÔØ�<‰<Ò#Ü�K‰KØOØ×"Ñ" D×$6Ñ$6¸×8JÑ8JÈD×L]ÑL]Ð_c×_tÑ_tôð ×!×!Ð!Ü�N‰Nð  Oô  PØ××ÐÜ�N‰NðSôð 	×"Ñ" 4Ô(Ùñ rùs%   ‚<H7ÁDH7Å H5Å!BH7Ç&&H7È)H7c               ó   € V ^8„  d   QhRR/# ©r.   r1   ÚNoner2   )r3   s   "r4   r5   rˆ   4  s   € ÷ 
"ñ 
" $ñ 
"r6   c              ƒ  	ó  "  € R F<  w  rp\        W4      pVf   K   \        WB4      ! 4       G Rj  x€L
  \	        WR4       K>  	  V P                  4        R#  L&  \         d    \        P                  RT4        LGi ; i5i)rÑ   Nz[whatsapp_cloud] %s failed))rÑ   Úcleanupzwebhook server cleanup)rÒ   Úaclosezhttp client close)ÚgetattrÚ	Exceptionr{   Ú	exceptionÚsetattrÚ_mark_disconnected)rÓ   ÚattrÚcloseÚwhatÚobjs   &    r4   Ú
disconnectÚWhatsAppCloudAdapter.disconnect4  s�   é € ó "EÑˆD˜Ü˜$Ó%ˆCØŠ{ÙðEÜ˜cÔ)Ó+×+Ð+ô �D Ö%ñ "Eð 	×ÑÖ!ñ	 ,øÜô EÜ× Ñ Ð!=¸tÖDðEüs7   ‚B �A°A±Aµ"B ÁAÁ!A=Á:B Á<A=Á=B c               ó    € V ^8„  d   QhRRRR/# )r.   Úrespr   r1   rZ   r2   )r3   s   "r4   r5   rˆ   B  s   € ÷ 
Iñ 
I˜cð 
I cñ 
Ir6   c                óš  €  V P                  4       pT;'       g    / P                  R4      ;'       g    / pVP                  R4      ;'       g    VP                  R4      ;'       g    RpVP                  R4      pVe   RV RV P                   R	V 2# R
V P                   RV 2#   \         d    RT P                  R,          /p L·i ; i)z;Map a non-200 Graph response to an actionable error string.rß   :Niô  NÚerrorr2  zunknown errorr1  zgraph error z (HTTP z): zHTTP z: )Újsonr=  r(   r;   Ústatus_code)rH  r?   Úerrr2  r1  s   &    r4   Ú_response_errorÚ$WhatsAppCloudAdapter._response_errorA  sÝ   € ð	,Ø—9‘9“;ˆDð �zˆz�r×Ñ˜wÓ'×-Ð-¨2ˆØ—'‘'˜)Ó$×JÐJ¨¯©°«×JÐJ¸?ˆØ�w‰w�v‹ˆØMQÒM]�˜d˜V 7¨4×+;Ñ+;Ð*<¸CÀ¸yÐIð  	IÐejÐko×k{Ñk{Ðj|Ð|~ð  @Gð  Hð  dIð  	Iøô ô 	,Ø˜4Ÿ9™9 T�?Ð+ŠDð	,ús   ‚B' Â' C
Ã	C
Úreject_argsc          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r.   Úpayloadr0   Úfail_logrZ   Ú
reject_logrP  Útupler1   ztuple[list, Optional[str]]r2   )r3   s   "r4   r5   rˆ   N  s6   € ÷ ñ ¨Nð Èð ÐZ]ð Ðlqð ð  |Vñ r6   c             ƒ  óZ  "  €  V P                   P                  V P                  R4      V P                  4       VR7      G Rj  x€L
 pTP                  ^È8w  d:   T P                  T4      p\
        P                  ! Y5P                  .TOTN5!   . T3#  TP                  4       P                  R4      ;'       g    . R3#  Lz  \         dJ   p\
        P                  T4       . \        T4      ;'       g    \        T4      P                  3u Rp?# Rp?ii ; i  \         d    . R3u # i ; i5i)zWPOST one /messages payload. Returns ``(response messages[], None)`` or ``([], error)``.Úmessages©rë   rK  N)rÒ   Úpostrå   rì   r=  r{   r>  rZ   ÚtypeÚ__name__rL  rN  r|   rK  r;   )rÓ   rR  rS  rT  rP  rH  rV   Ú	error_msgs   &&$$$   r4   Ú_post_messagesÚ#WhatsAppCloudAdapter._post_messagesN  s  é € ð	6Ø×*Ñ*×/Ñ/°·±À
Ó0KÐUY×UgÑUgÓUiÐpwÐ/Óx×xˆDð ×Ñ˜sÔ"Ø×,Ñ,¨TÓ2ˆIÜ�NŠN˜:×'7Ñ'7ÐQ¸+ÐQÀyÔQØ�y�=Ð ð	Ø—9‘9“;—?‘? :Ó.×4Ð4°"°dÐ:Ð:ñ yøÜô 	6Ü×Ñ˜XÔ&Ø”s˜3“x×5Ð5¤4¨£9×#5Ñ#5Ð5Õ5ûð	6ûô ô 	Ø�t�8ŠOð	üsq   ‚D+„>B? ÁB=ÁB? ÁA
D+Â%D Â8D Â<D+Â=B? Â?DÃ
>DÄDÄ	D+ÄDÄD+ÄD(Ä%D+Ä'D(Ä(D+c               ó    € V ^8„  d   QhRRRR/# )r.   rR  r0   r1   r   r2   )r3   s   "r4   r5   rˆ   ^  s   € ÷ Sñ S°.ð SÐS]ñ Sr6   c              ‹  óú   "  € V P                   f   \        RRR7      # V P                  ! V3/ VB G Rj  x€L
 w  r4Ve   \        RVR7      # \        RV'       d   V^ ,          P                  R4      MRR7      #  LD5i)u`   ``_post_messages`` â†’ SendResult with the first returned message id; guards disconnected state.NFúNot connected©ÚsuccessrJ  TÚid©rc  Ú
message_id)rÒ   r   r]  r;   )rÓ   rR  Ú
log_kwargsr÷   rM  s   &&,  r4   Ú_post_message_resultÚ)WhatsAppCloudAdapter._post_message_result^  s‹   é € à×ÑÒ$Ü e°?ÔCÐCØ×,Ò,¨WÑC¸
ÑC×C‰ˆØ7:²Œz %¨sÔ3ð  	SÌJÐ_c÷  EHÐpsÐtuÕpv×pzÑpzÐ{ô  qAð  NRô  MSð  	Sñ Dùs   ‚2A;´A9µAA;c          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r.   Úchat_idrZ   ÚkindÚblockr   Úreply_tor[   r1   r0   r2   )r3   s   "r4   r5   rˆ   f  s0   € ÷ ñ  3ð ¨cð ¸#ð Èð Ð[iñ r6   c           
     ó:   € RRRRRV RWV/pV'       d   RV/VR&   V# )	zJCommon ``/messages`` envelope; ``context`` quotes ``reply_to`` when given.Úmessaging_productÚwhatsappÚrecipient_typeÚ
individualÚtorZ  rf  Úcontextr2   )rk  rl  rm  rn  rR  s   &&&& r4   Ú_outbound_payloadÚ&WhatsAppCloudAdapter._outbound_payloade  sA   € ð $7¸
ÐDTÐVbÐdhÐjqÐsyÐ{ð  HMð  #NˆßØ".°Ð!9ˆG�IÑØˆr6   Nc          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r.   rk  rZ   rO   rn  r[   ro   rp   r1   r   r2   )r3   s   "r4   r5   rˆ   m  s<   € ÷ Dñ D #ð D°ð D¸}ð DÐ_wð Dð  DNñ Dr6   c           	   ƒ  óv  "  € V P                   f   \        RRR7      # V'       d   VP                  4       '       g   \        RRR7      # V P                  V4      pRp\	        V P                  WPP                  4       4      4       Fy  w  rxT P                  TRRVR	R/V^ 8X  d   TMR4      p	V P                  V	R
RR7      G Rj  x€L
 w  r«Ve   \        RVR7      u # V
'       d   V
^ ,          P                  R4      MTpK{  	  V'       d    \        P                  ! WV4      G Rj  x€L
  \        RVR7      #  Ls L5i)zLSend a text message via Graph API. ``chat_id`` is the recipient's ``wa_id``.NFra  rb  Tre  r(   r?   Úpreview_urlz[whatsapp_cloud] send failedz.[whatsapp_cloud] send rejected (status=%d): %s©rS  rT  rd  )rÒ   r   rj   Úformat_messageÚ	enumerateÚtruncate_messageÚ_outgoing_chunk_limitrv  r]  r;   r   Úrecord_async)rÓ   rk  rO   rn  ro   Ú	formattedÚlast_message_idÚidxÚchunkrR  r÷   rM  s   &&&&&       r4   ÚsendÚWhatsAppCloudAdapter.sendm  s%  é € à×ÑÒ$Ü e°?ÔCÐCß˜gŸm™mŸošoÜ d°tÔ<Ð<Ø×'Ñ'¨Ó0ˆ	Ø)-ˆÜ# D×$9Ñ$9¸)×E_ÑE_ÓEaÓ$bÖc‰JˆCà×,Ñ,Ø˜ &¨%°ÀÐ!EÐSVÐZ[ÔS[ÁxÐaeóˆGð "×0Ñ0ØØ7ØKð 1ó ÷ ‰HˆCð
 ŠÜ!¨%°sÔ;Ò;ß25˜c !�fŸj™j¨Ô.¸?ŠOñ d÷ Ü!×.Ò.¨wÈÓS×SÐSÜ $°?ÔCÐCññ Tùs:   ‚#D9¦D9¼BD9ÃD5Ã D9Ã#%D9Ä	D9Ä#D7Ä$D9Ä7D9c               ó    € V ^8„  d   QhRRRR/# )r.   rk  rZ   r1   r8  r2   )r3   s   "r4   r5   rˆ   ‰  s   € ÷ lñ l¨ð lÀñ lr6   c           	   ƒ  óŽ  "  € V P                   P                  V4      pV P                  e	   V'       g   R# RRRRRVRRR	//p V P                  P                  V P	                  R
4      V P                  4       VR7      G Rj  x€L
 pTP                  ^È8X  d   R#  TP                  4       ;'       g    / P                  R4      ;'       g    / P                  R4      pTR8X  d   \        P                  RT4       R# \        P                  RTP                  T4       R#  Lœ  \         d     R# i ; i  \         d    Rp Lei ; i5i)zåMark the latest inbound message read AND show a typing indicator. Meta couples
both into one POST; the indicator auto-dismisses on reply or after 25s. Best-effort:
every error is swallowed so the main reply path is never blocked.Nrp  rq  ÚstatusÚreadrf  Útyping_indicatorrZ  r(   rW  rX  rJ  r1  iÁÿ zS[whatsapp_cloud] typing/read indicator rejected: wamid %s likely older than 30 daysz7[whatsapp_cloud] typing/read indicator returned %d (%s))rÍ   r;   rÒ   rY  rå   rì   r=  rL  rK  r{   r.  Údebug)rÓ   rk  ro   ÚwamidrR  rH  r1  s   &&&    r4   Úsend_typingÚ WhatsAppCloudAdapter.send_typing‰  s0  é € ð ×0Ñ0×4Ñ4°WÓ=ˆØ×ÑÒ$¯EÙØ&¨
°H¸fÀlÐTYÐ[mÐpvÐx~Ðoð  Aˆð	Ø×*Ñ*×/Ñ/°·±À
Ó0KÐUY×UgÑUgÓUiÐpwÐ/Óx×xˆDð ×Ñ˜sÔ"Ùð	Ø—Y‘Y“[×&Ð& B×+Ñ+¨GÓ4×:Ð:¸×?Ñ?ÀÓGˆDð
 �6Œ>Ü�K‰KÐmÐotÖuä�L‰LÐRÐTX×TdÑTdÐfjÖkñ yøÜô 	Úð	ûô ô 	ØŠDð	üsq   ‚1E´EÁ>D  ÂDÂD  ÂEÂD2 Â1D2 Ã
D2 ÃAEÄD  Ä D/Ä+EÄ.D/Ä/EÄ2EÄ?EÅEÅEc               ó4   € V ^8„  d   QhRRRRRRRRR	RR
RRR/# )r.   rk  rZ   r*   r0   ro   rp   ÚstateúOrderedDict[str, str]Ústate_idÚsession_keyr1   r   r2   )r3   s   "r4   r5   rˆ   £  sF   € ÷ ñ ØðØ)7ðØC[ðà$ðà03ðàBEðð 
ñr6   c           
   ƒ  óÆ   "  € V P                  V P                  VRV\        V4      4      RRR7      G Rj  x€L
 pVP                  '       d   \	        WEV\
        4       V#  L)5i)u  POST an ``interactive`` message (caller supplies ``type``/``body``/``action``) and, on
success, remember ``state_id â†’ session_key`` for the tap. Free-form interactives need no
Meta approval but are only valid inside the 24h window â€” fine, all senders here reply to a user.r*   z([whatsapp_cloud] interactive send failedz5[whatsapp_cloud] interactive rejected (status=%d): %sr{  N)rh  rv  rs   rc  r   ÚINTERACTIVE_STATE_CACHE_SIZE)rÓ   rk  r*   ro   r‘  r“  r”  Úresults   &&&&&&& r4   Ú_send_interactiveÚ&WhatsAppCloudAdapter._send_interactive£  sc   é € ð ×0Ñ0Ø×"Ñ" 7¨M¸;ÌÐW_ÓH`ÓaØ?ØNð 1ó 
÷ 
ˆð
 �>�>ˆ>Ü˜¨Ô6RÔSØˆñ
ùs   ‚3A!µA¶A!ÁA!c               ó$   € V ^8„  d   QhRRRRRR/# ©r.   r(   rZ   ÚlimitrL   r1   r2   )r3   s   "r4   r5   rˆ   ´  s&   € ÷ Qñ Q Sð Q°ð Q¸cñ Qr6   c                ó¦   € \        T ;'       g    R4      P                  4       p \        V 4      V8:  d   V # V R\        ^V^,
          4       R,           # )zJButton titles cap at 20 chars, list-row titles at 24; the ellipsis counts.rg   Nu   â€¦)rZ   rj   rT   Úmax©r(   rœ  s   &&r4   Ú_truncate_button_labelÚ+WhatsAppCloudAdapter._truncate_button_label³  sJ   € ô �4—:�:˜2‹×$Ñ$Ó&ˆÜ˜4“y EÔ)ˆtÐP¨tÐ4G´c¸!¸UÀQ½YÓ6GÐ/HÈ5Õ/PÐPr6   c               ó$   € V ^8„  d   QhRRRRRR/# r›  r2   )r3   s   "r4   r5   rˆ   º  s&   € ÷ Iñ I˜Sð I¨ð I¸ñ Ir6   c                óv   € \        T ;'       g    R4      p \        V 4      V8:  d   V # V RV^,
           R,           # )z-``interactive.body.text`` caps at 1024 chars.rg   Nz...)rZ   rT   rŸ  s   &&r4   Ú_truncate_bodyÚ#WhatsAppCloudAdapter._truncate_body¹  s9   € ô �4—:�:˜2‹ˆÜ˜4“y EÔ)ˆtÐH¨t°K°e¸aµiÐ/@À5Õ/HÐHr6   c               ó    € V ^8„  d   QhRRRR/# )r.   Úbuttonsútuple[str, str]r1   zlist[dict[str, Any]]r2   )r3   s   "r4   r5   rˆ   À  s   € ÷ cñ c ð cÐ5Iñ cr6   c                 	óJ   € V  UUu. uF  w  rR RRRVRV//NK  	  upp# u uppi )rZ  Úreplyrd  rE   r2   )r§  ÚbidrE   s   *  r4   Ú_reply_buttonsÚ#WhatsAppCloudAdapter._reply_buttons¿  s0   € áZaÔbÑZaÉJÈC�˜ '¨D°#°wÀÐ+FÓGÑZaÒbÐbùÓbs   †c               ó$   € V ^8„  d   QhRRRRRR/# )r.   Ú	body_textrZ   r§  r¨  r1   r0   r2   )r3   s   "r4   r5   rˆ   Ä  s&   € ÷ tñ t¨Cð t¸?ð tÈ~ñ tr6   c           
     ó6   € RRRRV/RRV P                   ! V!  //# )uZ   ``interactive.type=button`` body: â‰¤3 quick-reply buttons (id â‰¤256 chars, title â‰¤20).rZ  r)   r?   r(   Úactionr§  )r¬  )Úclsr¯  r§  s   &&*r4   Ú_button_interactiveÚ(WhatsAppCloudAdapter._button_interactiveÃ  s.   € ð ˜ &¨6°9Ð*=¸xÈ)ÐUX×UgÒUgÐipÑUqÐIrÐsÐsr6   c               ó4   € V ^8„  d   QhRRRRRRRRRRRR	R
R/# )r.   rk  rZ   ÚquestionÚchoiceszOptional[list]Ú
clarify_idr”  ro   rp   r1   r   r2   )r3   s   "r4   r5   rˆ   È  sO   € ÷ #zñ #zØð#zØ&)ð#zØ4Bð#zØPSð#zàð#zà$<ð#zð 
ñ#zr6   c              ƒ  óX  a a"  € T;'       g    RP                  4       pV'       g)   S P                  VRV 2\        V4      R7      G Rj  x€L
 # VR,           Uu. uF=  p\        V4      P                  4       '       g   K$  \        V4      P                  4       NK?  	  ppS P	                  RV R2RP                  R \        V4       4       4      ,           4      p	\        V4      ^8:  d3   S P                  ! V	.VV 3R	 l\        \        V4      4       4       O5!  p
M×\        V4       UUu. uF=  w  r¼R
RS RV 2RS P                  V^,            ^R7      RS P                  V^HR7      /NK?  	  pppVP                  R
RS R2RS P                  \        R4      ^R7      RS P                  \        R4      ^HR7      /4       RRRRV	/RRS P                  \        R4      4      RR\        R4      RV/.//p
S P                  WVS P                  SV4      G Rj  x€L
 #  ELÐu upi u uppi  L5i)uê   Clarify as native buttons: 1â€“3 choices â†’ buttons, 4+ â†’ list (+ "Other" row that flips
the entry into text-capture mode), 0 â†’ plain text question. Button ``id`` carries
``cl:<clarify_id>:<idx|other>``; inbound dispatches on it.rg   u   â�“ )rn  N:Né
   Nú

rñ   c              3  óB   "  € T F  w  rV^,            RV 2x € K  	  R# 5i)é   z. Nr2   )rŒ   ÚiÚcs   &  r4   r�   Ú4WhatsAppCloudAdapter.send_clarify.<locals>.<genexpr>Õ  s(   é € ÐI~Ñf}Ñ^bÐ^_ÈQÐQRÍUÈGÐSUÐVWÐUXÍ/Óf}ùs   ‚c              3  óv   <"  € T F.  pR S RV 2SP                  \        V^,           4      4      3x € K0  	  R# 5i)úcl:Ú:N)r   rZ   )rŒ   rƒ  r¸  rÓ   s   & €€r4   r�   rÀ  Ø  sI   øé € ð  Hñ  oGÐgj  J <¨q°°Ð6¸×8SÑ8SÔTWÐX[Ð^_ÕX_ÓT`Ó8aÕbó  oGùs   ƒ69rd  rÂ  rÃ  rE   )rœ  Údescriptionz:otherz%platform.whatsapp.clarify_other_titlez+platform.whatsapp.clarify_other_descriptionrZ  Úlistr?   r(   r±  r)   z%platform.whatsapp.clarify_list_buttonÚsectionsz&platform.whatsapp.clarify_list_sectionÚrows)rj   r…  rs   rZ   r¤  Újoinr}  rT   r³  Úranger   Úappendr   r˜  rÎ   )rÓ   rk  r¶  r·  r¸  r”  ro   r¿  Úchoices_listr¯  r*   rƒ  Úchoice_textrÇ  s   f&&&f&&       r4   Úsend_clarifyÚ!WhatsAppCloudAdapter.send_clarifyÈ  sP  ùé € ð —N�N ×)Ñ)Ó+ˆßØŸ™ 7¨d°8°*Ð,=ÌÐW_ÓH`˜Óa×aÐað 18¸¶ÓO±¨1ÄÀAÃÇÁÇœœ˜A›Ÿ™ž±ˆÐOØ×'Ñ'¨$¨x¨j¸Ð(=ÀÇ	Á	ÑI~ÔfoÐp|Ôf}ÓI~Ó@~Õ(~Óˆ	Üˆ|Ó Ô!Ø×2Ò2Øðõ HÔnsÔtwð  yEó  uFô  oGó  Hó‰Kô )2°,Ô(?ôñ )@Ñ$�Cð ˜˜Z˜L¨¨#¨Ð/°¸$×:UÑ:UÐY\Ð_`ÕY`ÐXaÐjlÐ:UÓ:mØ × ;Ñ ;¸KÈrÐ ;Ó RóTá(?ð ñ ð
 �K‰KØ˜˜J˜< vÐ.Ø˜×4Ñ4´QÐ7^Ó5_ÐgiÐ4ÓjØ˜t×:Ñ:¼1Ð=jÓ;kÐsuÐ:Óvðô ð ˜ ¨°Ð(;Ø˜8 T×%@Ñ%@ÄÐCjÓAkÓ%lØ%¨´!Ð4\Ó2]Ð_eÐgkÐ(lÐ'mðoðˆKð
 ×+Ñ+¨GÀ(ÈD×L_ÑL_ÐakÐmxÓy×yÐyò5 bùò Pùóñ zùsI   „"H*§#H*Á
HÁH*Á!HÂ HÂBH*Ä*AH"Å-B(H*ÈH(ÈH*ÈH*c               ó   € V ^8„  d   QhRR/# rï   r2   )r3   s   "r4   r5   rˆ   î  s   € ÷ 2ñ 2˜Cñ 2r6   c                	ó   € R \        4        R2# )u   âš ï¸� *ú*

r   ró   s   &r4   Ú
_EA_HEADERÚWhatsAppCloudAdapter._EA_HEADERí  s   € àœ.Ó*Ð+¨5Ð1Ð1r6   z
```

i   c               ó    € V ^8„  d   QhRRRR/# )r.   Úpromptr   r1   r   r2   )r3   s   "r4   r5   rˆ   ô  s   € ÷ 	vñ 	vÐ7Ið 	vÈjñ 	vr6   c           
   ƒ  ó²  "  € \         P                  ! 4       P                  R,          pV P                  V P	                  VP
                  4      RV R2V P                  \        R4      4      3RV R2V P                  \        R4      4      34      pV P                  VP                  W1P                  V P                  W!P                  4      G Rj  x€L
 #  L5i)z™Approve / Deny buttons only (a 3-button cap leaves no room for the session/always
tiers); a tap resolves via ``tools.approval.resolve_gateway_approval``.:Né   Núappr:z:approvez platform.whatsapp.approve_buttonz:denyzplatform.whatsapp.deny_buttonN)ÚuuidÚuuid4Úhexr³  r¤  r(   r   r   r˜  rk  ro   rÏ   r”  )rÓ   rÕ  Úapproval_idr*   s   &&  r4   Ú_send_exec_approval_promptÚ/WhatsAppCloudAdapter._send_exec_approval_promptô  sÅ   é € ô —j’j“l×&Ñ& sÕ+ˆØ×.Ñ.Ø×Ñ §¡Ó,Ø�[�M Ð*¨D×,GÑ,GÌÐJlÓHmÓ,nÐoØ�[�M Ð'¨×)DÑ)DÄQÐGfÓEgÓ)hÐiókˆð ×+Ñ+Ø�N‰N˜K¯©¸$×:SÑ:SÐU`×btÑbtóv÷ vð 	vñ vùs   ‚CCÃCÃCc               ó4   € V ^8„  d   QhRRRRRRRRRRRRR	R
/# )r.   rk  rZ   rE   r2  r”  Ú
confirm_idro   rp   r1   r   r2   )r3   s   "r4   r5   rˆ   ÿ  sM   € ÷ 
@ñ 
@Øð
@Ø#&ð
@Ø14ð
@ØCFð
@ØTWð
@Øc{ð
@à	ñ
@r6   c              ƒ  óX  "  € V P                  V P                  RV RV 24      RV 2V P                  \        R4      4      3RV 2V P                  \        R4      4      3RV 2V P                  \        R4      4      34      pV P	                  WW`P
                  WT4      G R	j  x€L
 #  L5i)
zJApprove Once / Always / Cancel buttons; ``confirm_id`` is caller-supplied.Ú*rÑ  zsc:once:z$platform.whatsapp.slash_confirm_oncez
sc:always:z&platform.whatsapp.slash_confirm_alwaysz
sc:cancel:z&platform.whatsapp.slash_confirm_cancelN)r³  r¤  r   r   r˜  rÐ   )rÓ   rk  rE   r2  r”  rà  ro   r*   s   &&&&&&& r4   Úsend_slash_confirmÚ'WhatsAppCloudAdapter.send_slash_confirmÿ  s¶   é € ð ×.Ñ.Ø×Ñ ! E 7¨%°¨yÐ 9Ó:Ø˜
�|Ð$ d×&AÑ&AÄ!ÐDjÓBkÓ&lÐmØ˜*˜Ð&¨×(CÑ(CÄAÐFnÓDoÓ(pÐqØ˜*˜Ð&¨×(CÑ(CÄAÐFnÓDoÓ(pÐqó	
ˆð ×+Ñ+¨GÀ(×LeÑLeÐgqÓ×ÐÑùs   ‚B!B*Â#B(Â$B*c               ó    € V ^8„  d   QhRRRR/# )r.   rk  rZ   r1   r0   r2   )r3   s   "r4   r5   rˆ     s   € ÷ /ñ /¨3ð /°>ñ /r6   c              ƒ  	ó   "  € R VRR/# 5i)ru   rZ  Údmr2   )rÓ   rk  s   &&r4   Úget_chat_infoÚ"WhatsAppCloudAdapter.get_chat_info  s   é € à˜ ¨Ð.Ð.ùs   ‚	c               ó(   € V ^8„  d   QhRRRRRRRR/# )r.   Ú	file_pathrZ   Ú
media_kindÚ	mime_typer[   r1   ú#tuple[Optional[str], Optional[str]]r2   )r3   s   "r4   r5   rˆ     s3   € ÷ Xñ X¨Sð X¸cð XÈmð Xð  hKñ Xr6   c           
   ƒ  ór  "  € V P                   f   R# \        P                  P                  V4      '       g   RRV 23# \        P                  P	                  V4      \
        P                  V\
        R,          4      rTWE8”  d/   RR\        P                  P                  V4       RV RV RV R2	3# T;'       g<    \        P                  ! V4      ^ ,          ;'       g    \        P                  VR	4      p \        VR
4      ;_uu_ 4       pR\        P                  P                  V4      Wc3RRRRV3/pV P                   P                  V P                  R4      V P                  RR7      VR7      G Rj  x€L
 pRRR4       XP&                  ^È8w  d   RT P)                  T4      3#  TP+                  4       P                  R4      p
T
'       d   T
R3# R#  L^  + '       g   i     Ld; i  \         d-   p	\         P#                  R4       R\%        T	4      3u Rp	?	# Rp	?	ii ; i  \         d    Rp
 Lli ; i5i)zWUpload a local file to Graph /media. Returns ``(media_id, None)`` or ``(None, error)``.NzFile not found: r   zFile z is z bytes; Cloud API z cap is z bytesr"   ÚrbÚfilerp  rZ  ÚmediaF©rç   )rë   Úfilesz$[whatsapp_cloud] media upload failedrd  )Nra  )Nrq  )NzUpload response missing 'id')rÒ   ÚosrÛ   ÚexistsÚgetsizeÚ_MEDIA_SIZE_LIMITSr;   ÚbasenameÚ	mimetypesÚ
guess_typeÚ_DEFAULT_MIMEr˜   rY  rå   rì   r=  r{   r>  rZ   rL  rN  rK  )rÓ   rë  rì  rí  ÚsizeÚcapÚfhrô  rH  rV   Úmedia_ids   &&&&       r4   Ú_upload_mediaÚ"WhatsAppCloudAdapter._upload_media  s-  é € à×ÑÒ$Ø(Ð(Ü�w‰w�~‰~˜i×(Ò(ØÐ+¨I¨;Ð7Ð7Ð7Ü—G‘G—O‘O IÓ.Ô0B×0FÑ0FÀzÔSeÐfpÕSqÓ0rˆcØŒ:Ø˜5¤§¡×!1Ñ!1°)Ó!<Ð =¸TÀ$ÀÐGYÐZdÐYeÐemÐnqÐmrÐrxÐyÐyÐyØ÷  Að  A¤×!5Ò!5°iÓ!@ÀÕ!C÷  Að  AÄ}×GXÑGXÐYcÐeó  HAˆ	ð	"Ü�i ×&Ô&¨"Ø¤"§'¡'×"2Ñ"2°9Ó"=¸rÐ!MÐObÐdvÐx~ð  BFð  HQð  ARð  S�Ø!×.Ñ.×3Ñ3°D·O±OÀGÓ4LÐVZ×VhÑVhÐsxÐVhÓVyð  BGÐ3ó  H÷  H�÷ 'ð ×Ñ˜sÔ"Ø˜×-Ñ-¨dÓ3Ð3Ð3ð	Ø—y‘y“{—‘ tÓ,ˆH÷ $,�˜$ÐÐWÐ1WÐWñ H÷ '×&ûô ô 	"Ü×ÑÐCÔDØœ˜S›�>Õ!ûð	"ûô ô 	ØŠHð	üs¨   ‚5H7¸BH7Â;$H7Ã H7Ã8G* ÄA*GÅ6GÅ7GÅ;G* Æ$H7Æ(H$ ÇH7ÇH7ÇGÇG'	Ç"G* Ç&H7Ç'G* Ç*H!Ç5!HÈH!ÈH7ÈH!È!H7È$H4È1H7È3H4È4H7r   Ú
media_linkrG   Úfilenamern  c               ó8   € V ^8„  d   QhRRRRRRRRRRRRR	RR
R/# )r.   rk  rZ   rì  r   r[   r  rG   r  rn  r1   r   r2   )r3   s   "r4   r5   rˆ   )  sS   € ÷ 
ñ 
Øð
Ø(+ð
Ø:Gð
à!ð
à3@ð
ð  ð
ð 3@ð
ð 
ñ	
r6   c             ƒ  óX  "  € V P                   f   \        RRR7      # \        V4      \        V4      8X  d   \        RRR7      # V'       d   RV/MRV/pV'       d   VR9   d   WXR	&   V'       d   VR8X  d   WhR
&   V P                  V P	                  WW‡4      RRV3R7      G Rj  x€L
 #  L5i)z¦POST a media message referencing exactly one of an uploaded ``media_id`` or a public
``link``. Caption is accepted on image/video/document; filename on document only.NFra  rb  z1Exactly one of media_id or media_link must be setrd  Úlinkr   rG   r  z"[whatsapp_cloud] media send failedz=[whatsapp_cloud] media send rejected (status=%d, kind=%s): %s)rS  rT  rP  >   r   r   r   )rÒ   r   rd   rh  rv  )	rÓ   rk  rì  r   r  rG   r  rn  Úmedia_blocks	   &&&$$$$$ r4   Ú_send_mediaÚ WhatsAppCloudAdapter._send_media)  sµ   é € ð ×ÑÒ$Ü e°?ÔCÐCÜ�‹>œT *Ó-Ô-Ü eÐ3fÔgÐgß:B t¨XÑ&6ÈÐQ[ÐH\ˆß�zÐ%CÔCØ%,˜	Ñ"ß˜
 jÔ0Ø&.˜
Ñ#Ø×.Ñ.Ø×"Ñ" 7¸ÓNØ9ØVØ#˜ð	 /ó 
÷ 
ð 	
ñ 
ùs$   ‚A	B*ÁB*ÁB*Á/4B*Â#B(Â$B*rí  c               ó8   € V ^8„  d   QhRRRRRRRRRRRRR	RR
R/# )r.   rk  rZ   Úsourcerì  rG   r[   r  rn  rí  r1   r   r2   )r3   s   "r4   r5   rˆ   @  sP   € ÷ ñ ØðØ$'ðØ58ðØFSðàðà2?ðð !ðð 
ñ	r6   c          	   ƒ  ó¢  "  € RV/pVP                  \        4      '       g6   V P                  W#V4      G Rj  x€L
 w  ršV
'       d   \        RV
R7      # RV	/pV P                  ! W3RVRVRV/VB G Rj  x€L
 pVP
                  '       d»   VP                  '       d©   RV9   d¢   T;'       g<    \        P                  ! V4      ^ ,          ;'       g    \        P                  VR	4      p\        P                  ! WP                  W,3.4      G Rj  x€L
  V'       d*   \        P                  ! WP                  V4      G Rj  x€L
  V#  EL LÕ L< L5i)
uó   HTTPS URL â†’ ``link`` send (one fewer round trip); local path â†’ upload + ``id`` send.
Local sends are indexed in ``rich_sent_store`` so a later quote of the attachment can be
resolved (Meta's inbound ``context`` carries only the quoted id).r  NFrb  r   rG   r  rn  r"   )rÞ   Ú_HTTP_PREFIXESr  r   r	  rc  rf  rú  rû  rü  r;   r   Úrecord_media_asyncr€  )rÓ   rk  r  rì  rG   r  rn  rí  Úrefr   rM  r—  rY   s   &&&&$$$$     r4   Ú_send_media_from_path_or_linkÚ2WhatsAppCloudAdapter._send_media_from_path_or_link@  s(  é € ð *6°vÐ(>ˆØ× Ñ ¤×0Ò0Ø"&×"4Ñ"4°VÈÓ"S×S‰MˆHßÜ!¨%°sÔ;Ð;Ø˜xÐ(ˆCØ×'Ò'¨ÑzÀWÐzÐW_ÐzÐjrÐzÐvyÑz×zˆØ�>�>ˆ>˜f×/×/Ð/°JÀ#Ô4EØ×|Ð|¤	× 4Ò 4°VÓ <¸QÕ ?×|Ð|Ä=×CTÑCTÐU_Ða{ÓC|ˆDÜ!×4Ò4°W×>OÑ>OÐSYÐR`ÐQaÓb×bÐbßÜ%×2Ò2°7×<MÑ<MÈwÓW×WÐWØˆò Tñ {ñ cáWùsc   ‚5E·E¸;EÁ3E	Á4EÂ
EÂEÂ,$EÃ=EÄEÄEÄ$EÄ?EÅ EÅ	EÅEÅEc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r.   rk  rZ   Ú	image_urlrG   r[   rn  r1   r   r2   )r3   s   "r4   r5   rˆ   W  s<   € ÷ yñ y¨ð y¸ð yÀmð yÐfsð yð  JTñ yr6   c              ‹  	óF   "  € V P                  WR W4R7      G Rj  x€L
 #  L5i©r   ©rG   rn  N©r  )rÓ   rk  r  rG   rn  Úkwargss   &&&&&,r4   Ú
send_imageÚWhatsAppCloudAdapter.send_imageW  s$   é € Ø×7Ñ7¸ÈGÐ]dÐ7Óx×xÐxÑxùó   ‚!š›!c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r.   rk  rZ   Ú
image_pathrG   r[   rn  r1   r   r2   )r3   s   "r4   r5   rˆ   Z  s<   € ÷ zñ z¨Sð z¸cð zÈMð zÐlyð zð  PZñ zr6   c              ‹  	óF   "  € V P                  WR W4R7      G Rj  x€L
 #  L5ir  r  )rÓ   rk  r  rG   rn  r  s   &&&&&,r4   Úsend_image_fileÚ$WhatsAppCloudAdapter.send_image_fileZ  ó$   é € Ø×7Ñ7¸ÈWÐ^eÐ7Óy×yÐyÑyùr  c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r.   rk  rZ   Ú
video_pathrG   r[   rn  r1   r   r2   )r3   s   "r4   r5   rˆ   ]  s<   € ÷ zñ z¨ð z¸ð zÀ}ð zÐgtð zð  KUñ zr6   c              ‹  	óF   "  € V P                  WR W4R7      G Rj  x€L
 #  L5i)r   r  Nr  )rÓ   rk  r$  rG   rn  r  s   &&&&&,r4   Ú
send_videoÚWhatsAppCloudAdapter.send_video]  r"  r  c               ó0   € V ^8„  d   QhRRRRRRRRRRRR	/# )
r.   rk  rZ   rë  rG   r[   Ú	file_namern  r1   r   r2   )r3   s   "r4   r5   rˆ   `  s@   € ÷ 
ñ 
Øð
Ø'*ð
Ø5Bð
ØVcð
ð wDð
à	ñ
r6   c           	   ‹  	ó–   "  € T P                  YR Y4;'       g     \        P                  P                  V4      VR7      G Rj  x€L
 #  L5i)r   )rG   r  rn  N)r  rõ  rÛ   rù  )rÓ   rk  rë  rG   r)  rn  r  s   &&&&&&,r4   Úsend_documentÚ"WhatsAppCloudAdapter.send_document`  sR   é € ð ×7Ñ7Ø 
°G×FnÐFnÔSU×SZÑSZ×ScÑScÐdmÓSnð  zBð 8ó 
÷ 
ð 	
ñ 
ùs   ‚A A	ÁAÁA	c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r.   rk  rZ   Ú
audio_pathrG   r[   rn  r1   r   r2   )r3   s   "r4   r5   rˆ   g  s<   € ÷ Oñ O¨ð O¸ð OÀ}ð OÐgtð Oð  KUñ Or6   c           	   ‹  óú  "  € RpVP                  \        4      '       gÍ   VP                  4       P                  R4      '       d¨   \        P
                  P                  V4      '       dƒ   V P                  V4      G Rj  x€L
 pV'       d`    V P                  WRW4RR7      G Rj  x€L
 \        P                  ! \        4      ;_uu_ 4        \        P                  ! V4       RRR4       # RpV P                  WRW4VR7      G Rj  x€L
 #  LŠ Lf  + '       g   i     # ; i  \        P                  ! \        4      ;_uu_ 4        \        P                  ! T4       RRR4       i   + '       g   i     i ; i; i Lt5i)z¡Voice message: ``audio/ogg; codecs=opus`` renders as a voice bubble, so a
local MP3 (Hermes TTS output) is converted via ffmpeg first; other audio is sent as-is.Nz.mp3r   zaudio/ogg; codecs=opus)rG   rn  rí  r!   )rÞ   r  rk   Úendswithrõ  rÛ   rö  Ú_convert_to_opusr  Ú
contextlibÚsuppressÚOSErrorÚunlink)rÓ   rk  r.  rG   rn  r  rí  Ú	opus_paths   &&&&&,  r4   Ú
send_voiceÚWhatsAppCloudAdapter.send_voiceg  s,  é € ð $(ˆ	Ø×$Ñ$¤^×4Ò4¸×9IÑ9IÓ9K×9TÑ9TÐU[×9\Ò9\Ôac×ahÑah×aoÑaoÐpz×a{Òa{Ø"×3Ñ3°JÓ?×?ˆIßð-Ø!%×!CÑ!CØ¨G¸WÐc{ð "Dó "÷ ô $×,Ò,¬W×5Õ5ÜŸ	š	 )Ô,÷ 6Ð5ð %ˆIØ×7Ñ7¸ÈWÐ^eð  ENÐ7ó  O÷  Oð  	Oñ @ñ÷ 6×5ûœ×,Ò,¬W×5Õ5ÜŸ	š	 )Ô,÷ 6×5×5Ð5ýñ Oùs„   ‚AE;Á$E;Á*E;Á>D	Á?E;ÂD  Â$DÂ%D  Â("E;Ã
DÃ!#E;ÄE9ÄE;ÄD  ÄDÄE;Ä #E6ÅE#	Å	E6Å#E3Å.E6Å6E;c               ó    € V ^8„  d   QhRRRR/# )r.   Úmp3_pathrZ   r1   r[   r2   )r3   s   "r4   r5   rˆ   y  s   € ÷ yñ y¨sð y°}ñ yr6   c              ƒ  ó
  "  € \         '       g1   V P                  '       g   RV n        \        P                  R4       R# \        P
                  ! \        WP                  R^4      ^ ,          R,           R7      G Rj  x€L
 #  L5i)u·   MP3 â†’ ``audio/ogg; codecs=opus`` sibling file; None if ffmpeg is missing or fails. The
missing-ffmpeg warning fires once per adapter: it is an install hint, not a per-message error.Tu  [whatsapp_cloud] ffmpeg not found on PATH â€” voice messages will be delivered as MP3 audio attachments instead of native voice notes (green waveform bubble). Install ffmpeg to enable: Windows `winget install Gyan.FFmpeg`, macOS `brew install ffmpeg`, Linux package manager.NÚ.r$   )Úoutput_path)Ú_FFMPEG_PATHrÌ   r{   r|   rQ   Ú	to_threadr   Úrsplit)rÓ   r:  s   &&r4   r1  Ú%WhatsAppCloudAdapter._convert_to_opusy  sl   é € ÷ ‹|Ø×)×)Ð)Ø)-�Ô&Ü—‘ðpôñ
 Ü×&Ò&Ô'<¸h×TcÑTcÐdgÐijÓTkÐlmÕTnÐqwÕTwÔx×xÐxÑxùs   ‚B¡ABÁ<BÁ=Bc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r.   ÚurlrZ   rë   r%   rC  r   r1   r   r2   )r3   s   "r4   r5   rˆ   ˆ  s1   € ÷ 
ñ 
 Cð 
°.ð 
Èð 
ÐWZð 
Ð_bñ 
r6   c              ƒ  ó  "  €  V P                   P                  WR7      G Rj  x€L
 pTP
                  ^È8w  d$   \        P                  RY4TP
                  4       R# T#  L:  \         d    \        P	                  RY44        R# i ; i5i)zSGET with the download path's uniform failure logging; None on exception or non-200.)rë   Nz.[whatsapp_cloud] media %s fetch raised (id=%s)z9[whatsapp_cloud] media %s fetch failed (id=%s, status=%d))rÒ   r;   r=  r{   r>  rL  r|   )rÓ   rC  rë   rC  r   rH  s   &&&&& r4   Ú
_graph_getÚWhatsAppCloudAdapter._graph_getˆ  s   é € ð	Ø×*Ñ*×.Ñ.¨sÐ.ÓD×DˆDð ×Ñ˜sÔ"Ü�N‰NÐVÐX\Ðhl×hxÑhxÔyÙØˆñ EøÜô 	Ü×ÑÐMÈtÔ^Úð	üs7   ‚B„A  £A¤A  ¨6BÁA  Á !BÂBÂBÂBÚext_hintc               ó$   € V ^8„  d   QhRRRRRR/# )r.   r   rZ   rG  r[   r1   rî  r2   )r3   s   "r4   r5   rˆ   ”  s&   € ÷ !+ñ !+°sð !+Èð !+ð  cFñ !+r6   c             ƒ  ó¦  "  € V P                   f   R# \        V4      P                  4       p\        P                  ! RV4      '       g    \
        P                  RVR,          4       R# V P                  RR7      pV P                  \         RV P                   RV 2VRV4      G Rj  x€L
 pVf   R#  VP                  4       pVP                  R	4      VP                  R
4      ;'       g    RrvV'       g   R# V P                  WcRV4      G Rj  x€L
 pVf   R# \        P                  RRR7       \        T T;'       g    \!        V4      ;'       g    R 2,          p	 V	P#                  VP$                  4       \        T	4      T;'       g    R3#  Lé  \         d    / p Lßi ; i L—  \&         d    \
        P)                  RT4       Ru # i ; i5i)uŸ   Two-step Graph download: ``GET /<id>`` â†’ signed temp URL (~5 min) â†’ bytes.
Returns ``(local_path, mime_type)`` or ``(None, None)`` on any failure (logged).Nz[A-Za-z0-9._-]+z/[whatsapp_cloud] refusing malformed media id %r:Né@   NFró  rÝ   ro   rC  rí  rg   rM   T)ÚparentsÚexist_okz.binz5[whatsapp_cloud] failed to write cached media (id=%s)©NN)rÒ   rZ   rj   rû   Ú	fullmatchr{   r|   rì   rE  rã   r¼   rK  r=  r;   Ú_INBOUND_MEDIA_CACHEÚmkdirra   Úwrite_bytesrO   r4  r>  )
rÓ   r   rG  rë   Ú	meta_respÚmetaÚtemp_urlrY   Ú	blob_respÚout_paths
   &&$       r4   Ú_download_media_to_cacheÚ-WhatsAppCloudAdapter._download_media_to_cache”  sÃ  é € ð ×ÑÒ$ØÐô �x“=×&Ñ&Ó(ˆÜ�|Š|Ð.°×9Ò9Ü�N‰NÐLÈhÐWZÍmÔ\ØÐØ×$Ñ$¨uÐ$Ó5ˆØŸ/™/¬^Ð,<¸A¸d×>OÑ>OÐ=PÐPQÐRZÐQ[Ð*\Ð^eÐgqÐs{Ó|×|ˆ	ØÒØÐð	Ø—>‘>Ó#ˆDð Ÿ™ %›¨$¯(©(°;Ó*?×*EÐ*EÀ2�$ßØÐàŸ/™/¨(¸WÀhÓO×Oˆ	ØÒØÐÜ×"Ñ"¨4¸$Ð"Ô?Ü'¨X¨J°x×7`Ð7`Ä=ÐQUÓCV×7`Ð7`ÐZ`Ð6aÐ*bÕbˆð	Ø× Ñ  ×!2Ñ!2Ô3ô �8‹}˜dŸl˜l dÐ*Ð*ñ+ }øô
 ô 	ØŠDð	úñ Pøô ô 	Ü×ÑÐTÐV^Ô_ØÒð	üs~   ‚B%GÂ'FÂ(
GÂ3F Ã'GÃ+#GÄF&Ä0GÅ GÅGÅF( Å:GÆGÆF#Æ GÆ"F#Æ#GÆ(#GÇGÇGÇGc               ó    € V ^8„  d   QhRRRR/# ©r.   rJ   zweb.Requestr1   zweb.Responser2   )r3   s   "r4   r5   rˆ   ¸  s   € ÷ ñ ¨Kð ¸Lñ r6   c              ƒ  	óB  "  € \         P                  ! R RRV P                  P                  RV P                  RV P
                  R\        V P                  4      R\        V P                  4      R\        RJR	V P                  R
V P                  RV P                  /
4      # 5i)r‰  r0  ÚplatformrŸ   r“   Úverify_token_configuredÚapp_secret_configuredÚffmpeg_presentNÚacceptedÚ
duplicatesÚrejected_signature)r   Újson_responser\  Úvaluer­   r¹   rd   r²   r°   r>  rÊ   rÉ   rË   )rÓ   rJ   s   &&r4   r(  Ú#WhatsAppCloudAdapter._handle_health¸  s“   é € Ü× Ò Ø�d˜J¨¯©×(;Ñ(;Ð=NÐPT×PeÑPeØ˜D×.Ñ.Ð0IÌ4ÐPT×PbÑPbÓKcØ#¤T¨$×*:Ñ*:Ó%;Ð=MÌ|ÐcgÐOgØ˜×,Ñ,¨l¸D×<QÑ<QØ  $×"@Ñ"@ð"
ó ð 	ùs   ‚BBc               ó    € V ^8„  d   QhRRRR/# rZ  r2   )r3   s   "r4   r5   rˆ   Á  s   € ÷ Pñ P¨Kð P¸Lñ Pr6   c              ƒ  óH  "  € V P                   '       g   \        P                  ! RRR7      # VP                  pVP	                  RR4      R8w  d   \        P                  ! RRR7      # \
        P                  ! VP	                  R	R4      P                  4       V P                   P                  4       4      '       g   \        P                  ! R
RR7      # VP	                  RR4      '       g   \        P                  ! RRR7      # \        P                  ! VR,          RR7      # 5i)zMeta subscription handshake: echo ``hub.challenge`` iff mode is
``subscribe`` and ``hub.verify_token`` matches (constant-time).é÷  zverify_token not configured©r‰  r(   zhub.moderg   Ú	subscribeé�  zbad modezhub.verify_tokeni“  zverify_token mismatchzhub.challengezmissing challengez
text/plain)r(   Úcontent_type)r²   r   ÚResponseÚqueryr;   ÚhmacÚcompare_digestÚencode)rÓ   rJ   Úqs   && r4   r)  Ú#WhatsAppCloudAdapter._handle_verifyÁ  sÔ   é € ð ×!×!Ð!ä—<’< sÐ1NÔOÐOØ�M‰MˆØ�5‰5�˜RÓ  KÔ/Ü—<’< s°Ô<Ð<ä×"Ò" 1§5¡5Ð);¸RÓ#@×#GÑ#GÓ#IÈ4×K]ÑK]×KdÑKdÓKf×gÒgÜ—<’< sÐ1HÔIÐIØ�u‰u�_ b×)Ò)Ü—<’< sÐ1DÔEÐEÜ�|Š|  ?Õ!3À,ÔOÐOùs   ‚B8D"Â;/D"Ã+7D"c               ó    € V ^8„  d   QhRRRR/# rZ  r2   )r3   s   "r4   r5   rˆ   Ñ  s   € ÷ (ñ (¨[ð (¸\ñ (r6   c              ƒ  ó˜  "  €  \        V\        4      G Rj  x€L
 pT P                  '       g.   \        P                  R4       \        P                  ! RRR7      # TP                  P                  R	R
4      pT P                  Y#4      '       gQ   T ;P                  ^,          un        \        P                  RT\        T4      4       \        P                  ! RR7      #  \        P                   ! T4      p\#        T\$        4      '       g   \        P                  ! RR7      # T P'                  T4      G Rj  x€L
  \        P                  ! ^ÈR7      #  EL;  \         d    \        P                  ! RR7      u # \
         d    \        P                  ! RR7      u # i ; i  \
         d    \        P                  R4       Rp LÏi ; i L‘5i)u  Inbound webhook POST: raw bytes â†’ HMAC verify â†’ JSON â†’ dispatch. Signature is over
the raw body, so JSON parsing must come after verification. Always 200 once a valid
request is ack'd â€” Meta retries non-200 for up to 7 days and would multiply agent work.Ni�  )r‰  rk  zr[whatsapp_cloud] webhook POST refused: app_secret unset. Set WHATSAPP_CLOUD_APP_SECRET to enable inbound delivery.rh  zapp_secret not configuredri  zX-Hub-Signature-256rg   zW[whatsapp_cloud] rejected webhook: invalid X-Hub-Signature-256 (header=%r, body_len=%d)i‘  z/[whatsapp_cloud] webhook body is not valid JSON)rW   r%  rU   r   rm  r=  r°   r{   rJ  rë   r;   Ú_verify_signaturerË   r|   rT   rK  Úloadsr  r  Ú_dispatch_payload)rÓ   rJ   rß   Úsignature_headerrR  s   &&   r4   r+  Ú$WhatsAppCloudAdapter._handle_webhookÑ  sw  é € ð
	,Ü2°7Ô<RÓS×SˆCð ××ÐÜ�L‰Lð  Nô  OÜ—<’< sÐ1LÔMÐMØ"Ÿ?™?×.Ñ.Ð/DÀbÓIÐØ×%Ñ% c×<Ò<Ø×*Ò*¨aÕ/Õ*Ü�N‰NÐtð  wGô  ILð  MPó  IQô  RÜ—<’< sÔ+Ð+ð	Ü—j’j “oˆGô ˜'¤4×(Ò(Ü—<’< sÔ+Ð+Ø×$Ñ$ WÓ-×-Ð-Ü�|Š| 3Ô'Ð'ò/ TøÜô 	,Ü—<’< sÔ+Ò+Üô 	,Ü—<’< sÔ+Ò+ð	,ûô ô 	Ü�N‰NÐLÔMØŠGð	úñ
 	.ùs€   ‚G
„E —E˜E œG
®B0G
ÃF  Ã5AG
Ä6GÄ7G
ÅE Å"FÅ7G
Å9FÆFÆG
ÆFÆG
Æ "GÇG
ÇGÇG
c               ó$   € V ^8„  d   QhRRRRRR/# )r.   Úraw_bodyrM   ÚheaderrZ   r1   rd   r2   )r3   s   "r4   r5   rˆ   ð  s&   € ÷ ]ñ ]¨%ð ]¸ð ]Àñ ]r6   c                óÞ  € V P                   '       d?   V'       d7   VP                  R4      '       d    VR,          P                  4       ;p'       g   R# \        P                  ! V P                   P                  R4      V\        P                  4      P                  4       p\        P                  ! VP                  4       P                  4       VP                  4       P                  4       4      # )zUVerify ``sha256=<hex>`` HMAC of the raw body keyed by ``app_secret`` (constant-time).zsha256=:é   NNFzutf-8)r°   rÞ   rj   ro  Únewrq  ÚhashlibÚsha256Ú	hexdigestrp  rk   )rÓ   r|  r}  Úexpected_hexÚcomputeds   &&&  r4   rv  Ú&WhatsAppCloudAdapter._verify_signatureð  s£   € à× × Ð §V°×0AÑ0AÀ)×0LÒ0LÐbhÐikÕbl×brÑbrÓbtÐRtÐR^ÖRtÙÜ—8’8˜D×,Ñ,×3Ñ3°GÓ<¸hÌÏÉÓW×aÑaÓcˆä×"Ò" 8§>¡>Ó#3×#:Ñ#:Ó#<¸l×>PÑ>PÓ>R×>YÑ>YÓ>[Ó\Ð\r6   c               ó    € V ^8„  d   QhRRRR/# )r.   r�  rZ   r1   rd   r2   )r3   s   "r4   r5   rˆ   ù  s   € ÷ ñ  #ð ¨$ñ r6   c                ó¤   € WP                   9   d   V ;P                  ^,          un        R# V'       d   \        V P                   VR\        4       R# )zITrue if this wamid is new; False (and count a duplicate) if already seen.FT)rÈ   rÉ   r   ÚWAMID_DEDUP_CACHE_SIZE)rÓ   r�  s   &&r4   Ú_dedup_wamidÚ!WhatsAppCloudAdapter._dedup_wamidù  s=   € à×%Ñ%Ô%Ø×!Ò! QÕ&Õ!ÙßÜ˜×)Ñ)¨5°$Ô8NÔOÙr6   c               ó    € V ^8„  d   QhRRRR/# )r.   rR  r0   r1   r8  r2   )r3   s   "r4   r5   rˆ     s   € ÷ %rñ %r¨~ð %rÀ$ñ %rr6   c              ƒ  óþ  "  € VP                  R4      R8w  d(   \        P                  RVP                  R4      4       R# VP                  R4      ;'       g    .  EF  p\        V\        4      '       d   VP                  R4      ;'       g    . M.  EFØ  p\        V\        4      '       d   VP                  R4      R8w  d   K2  VP                  R	4      ;'       g    / p\        V\        4      '       g   Ke  VP                  R
4      ;'       g    / pV P                  VP                  R4      V4      '       g§   \        P                  VP                  R4      '       d   \        P                  M\        P                  RVP                  R4      \        V\        4      '       d   VP                  R4      MRV P                  ;'       g    RV P                  4       EKM  VP                  R4      ;'       g    .  Uu/ uF£  p\        V\        4      '       g   K  \        VP                  R4      ;'       g    R4      P                  4       ;p'       g   KW  T\        VP                  R4      ;'       g    / P                  R4      ;'       g    R4      P                  4       bK¥  	  ppVP                  R4      ;'       g    .  F5  p	\        V	\        4      '       g   K  V P                  W˜V4      G Rj  x€L
  K7  	  VP                  R4      ;'       g    .  FP  p
\        V
\        4      '       g   K  \        P                  RV
P                  R4      V
P                  R4      4       KR  	  EKÛ  	  EK  	  R# u upi  Lˆ5i)u¼   Walk ``entry[].changes[].value.{messages, contacts, statuses}`` and dispatch each message.
``statuses`` (sent/delivered/read/failed) are only logged â€” the agent doesn't consume receipts.ÚobjectÚwhatsapp_business_accountz6[whatsapp_cloud] ignoring non-WABA payload (object=%r)Nrþ   ÚchangesÚfieldrW  rd  ro   rd  zo[whatsapp_cloud] ignoring signed webhook for waba=%r phone_number_id=%r (configured waba=%s phone_number_id=%r)rŸ   z<any>r,   Úwa_idrg   Úprofileru   Ústatusesz![whatsapp_cloud] status %s for %sr‰  )r;   r{   rŒ  r  r  r  ÚlogÚloggingÚWARNINGÚDEBUGr±   r­   rZ   rj   Ú_ingest_message)rÓ   rR  rþ   Úchangerd  ro   Úcontactr’  Úcontacts_by_waidr/   r‰  s   &&         r4   rx  Ú&WhatsAppCloudAdapter._dispatch_payload  s¿  é € ð �;‰;�xÓ Ð$?Ô?Ü�L‰LÐQÐSZ×S^ÑS^Ð_gÓShÔiÙØ—[‘[ Ó)×/Ð/¨RÓ/ˆEÜ:DÀUÌD×:QÒ:Q˜5Ÿ9™9 YÓ/×5Ð5°2øÐWYÓY�Ü! &¬$×/Ò/°6·:±:¸gÓ3FÈ*Ô3TÙØŸ
™
 7Ó+×1Ð1¨r�Ü! %¬×.Ò.ÙØ Ÿ9™9 ZÓ0×6Ð6°B�Ø×5Ñ5°e·i±iÀ³oÀx×PÒPô —J‘JØ+0¯9©9°Z×+@Ò+@œŸšÄgÇmÁmðBàŸ	™	 $›Ü;EÀhÔPT×;UÒ;U˜Ÿ™Ð%6Ô7Ð[_ØŸ™×0Ð0¨Ø×-Ñ-ôò ð $)§9¡9¨ZÓ#8×#>Ð#>¸BÐ#>ó$á#>˜Ü! '¬4×0ô Yä?BÀ7Ç;Á;ÈwÓCW×C]ÐC]Ð[]Ó?^×?dÑ?dÓ?fÐ6f°eÓ6fô Y�Eœ3 §¡¨IÓ 6× <Ð <¸"×AÑAÀ&ÓI×OÐOÈRÓP×VÑVÓXÒXÙ#>ð !ð $ð
 $)§9¡9¨ZÓ#8×#>Ð#>¸BÒ#>�KÜ! +¬t×4Ô4Ø"×2Ñ2°;ÐRZÓ[×[Ò[ñ $?ð $Ÿi™i¨
Ó3×9Ð9°rÒ9�FÜ! &¬$×/Ô/ÜŸ™Ð%HÈ&Ï*É*ÐU]ÓJ^Ð`f×`jÑ`jÐkoÓ`pÖqô :ô9 Zó 0ùò*$ñ \ùs‡   ‚AM=Á4M=ÂAM=Ã2M=Ä)M=Ä9%M=ÅA*M=Ç
,M=Ç7M=Ç<M6ÈM6È6M6ÉM6É3M6ÊM6Ê%M=Ê?M=ËM=Ë2M;
Ë3M=ÌM=Ì1AM=c               ó(   € V ^8„  d   QhRRRRRRRR/# )r.   r/   r0   rœ  r%   ro   r1   r8  r2   )r3   s   "r4   r5   rˆ   )  s5   € ÷ [ñ [°ð [ÐSað [Ðm{ð [ð  AEñ [r6   c              ƒ  ó   "  € \        VP                  R4      ;'       g    R4      P                  4       pV P                  V4      '       g   \        P                  RV4       R#  V P                  WV4      G Rj  x€L
 pTf   R# T ;P                  ^,          un	         T P                  T4      G Rj  x€L
  R#  L?  \         d    \        P                  RT4        R# i ; i L0  \         d    \        P                  RT4        R# i ; i5i)uå   Dedup â†’ build event â†’ handle_message. Neither build nor dispatch errors may
bubble out: the wamid is already dedup-marked, so a 500 would make Meta retry
the batch and every message in it would then be dropped as a duplicate.rd  rg   z-[whatsapp_cloud] duplicate wamid %s, skippingNz3[whatsapp_cloud] failed to build event for wamid %sz3[whatsapp_cloud] handle_message raised for wamid %s)rZ   r;   rj   rŠ  r{   rŒ  Ú_build_message_event_from_cloudr=  r>  rÊ   Úhandle_message)rÓ   r/   rœ  ro   r�  Úevents   &&&&  r4   r™  Ú$WhatsAppCloudAdapter._ingest_message)  sï   é € ô �K—O‘O DÓ)×/Ð/¨RÓ0×6Ñ6Ó8ˆØ× Ñ  ×'Ò'Ü�L‰LÐHÈ%ÔPÙð	Ø×>Ñ>¸{Ð^fÓg×gˆEð Š=ÙØ×Ò Õ!Õð	[Ø×%Ñ% eÓ,×,Ò,ñ høÜô 	Ü×ÑÐRÐTYÔZÚð	úñ -øÜô 	[Ü×ÑÐRÐTY×Zð	[üsx   ‚A	DÁDÁ%B< Á:B:Á;B< Á?DÂC& Â3C$Â4C& Â8DÂ:B< Â<!C!ÃDÃ C!Ã!DÃ$C& Ã&!DÄDÄ
DÄDc               ó$   € V ^8„  d   QhRRRRRR/# )r.   r/   r0   rœ  r%   r1   rd   r2   )r3   s   "r4   r5   rˆ   >  s(   € ÷ Uñ U¸^ð UÐ_mð UÐrvñ Ur6   c              ƒ  óš  a"  € \        V4      p\        VP                  R4      ;'       g    R4      P                  4       o\        VP                  R4      ;'       g    R4      P                  4       pS'       g   R# V'       d   V P	                  V4      '       g$   \
        P                  RT;'       g    RS4       R# SP                  R^4      p\        V3R	 lV P                  P                  4        4       R
4      pVe   \        V4      ^8w  d   R# T! T \        VP                  R4      ;'       g    R4      W54      G R
j  x€L
 #  L5i)ué   Route an inbound button tap to its resolver (see ``_INTERACTIVE_HANDLERS``). True = claimed.
False (unknown prefix, no live state, or no waiter) makes the caller fall back to text
dispatch with the button title â€” covers stale taps.rd  rg   ÚfromFzM[whatsapp_cloud] Rejected unauthorized interactive tap from %s (button_id=%r)z	<unknown>TrÃ  c              3  ó^   <"  € T F"  w  rSP                  V4      '       g   K  Vx € K$  	  R # 5i©N)rÞ   )rŒ   ÚprefixÚhÚ	button_ids   &  €r4   r�   ÚCWhatsAppCloudAdapter._dispatch_interactive_reply.<locals>.<genexpr>M  s&   øé € ÐnÑ+M™i˜fÐQZ×QeÑQeÐfl×QmŸšÓ+Mùs   ƒ-£
-N)r=   rZ   r;   rj   Ú_is_dm_allowedr{   r|   rý   ÚnextÚ_INTERACTIVE_HANDLERSÚitemsrT   )rÓ   r/   rœ  ÚinnerÚ	sender_idÚpartsÚhandlerr«  s   &&&    @r4   Ú_dispatch_interactive_replyÚ0WhatsAppCloudAdapter._dispatch_interactive_reply>  s  øé € ô # ;Ó/ˆÜ˜Ÿ	™	 $›×-Ð-¨2Ó.×4Ñ4Ó6ˆ	Ü˜Ÿ™¨Ó/×5Ð5°2Ó6×<Ñ<Ó>ˆ	ßÙ÷ ˜d×1Ñ1°)×<Ò<Ü�N‰NÐjÐlu÷  mEð  mEð  zEð  GPô  QÙØ—‘  QÓ'ˆÜÔn¨4×+EÑ+E×+KÑ+KÔ+MÓnÐptÓuˆàŠ?œc %›j¨AœoÙÙ˜T¤3 {§¡°vÓ'>×'DÐ'DÀ"Ó#EÀuÓT×TÐTÑTùs7   ƒAEÁEÁ;	EÂEÂEÂ5A?EÄ5EÅE	ÅEc               ó(   € V ^8„  d   QhRRRRRRRR/# )r.   rt  rZ   r(   rS  r1   r8  r2   )r3   s   "r4   r5   rˆ   S  s(   € ÷ 'ñ '¨3ð '°cð 'ÀSð 'ÈTñ 'r6   c              ƒ  	ó”   "  €  V P                  W4      G R j  x€L
  R #  L  \         d    \        P                  T4        R # i ; i5ir¨  )r…  r=  r{   r>  )rÓ   rt  r(   rS  s   &&&&r4   Ú_reply_best_effortÚ'WhatsAppCloudAdapter._reply_best_effortS  s8   é € ð	'Ø—)‘)˜BÓ%×%Ô%øÜô 	'Ü×Ñ˜X×&ð	'üs1   ‚A„! ˜™! �AŸ! ¡ AÁAÁAÁAc               ó0   € V ^8„  d   QhRRRRRRRRRRR	R
/# )r.   r‘  r’  r�   rZ   Ú	stale_logÚchoiceÚvalidrU  r1   r[   r2   )r3   s   "r4   r5   rˆ   Z  s<   € ÷ ñ Ø$ðØ+.ðØ;>ðØHKðØY^ðà	ñr6   c                ó�   € V P                  VR4      pV'       g   \        P                  W!4       V# V'       d   W49  d   WPV&   R# V# )u¯   Pop the session_key for a tapped prompt. None (info-logged) when nothing is live â€” likely
a stale tap; an unrecognised ``choice`` keeps the prompt live and also yields None.N)Úpopr{   r.  )r‘  r�   r¼  r½  r¾  r”  s   &&&&& r4   Ú_pop_tap_stateÚ#WhatsAppCloudAdapter._pop_tap_stateY  sE   € ð —i‘i  TÓ*ˆßÜ�K‰K˜	Ô'ð Ð÷ �vÔ*Ø$�#‰JÙØÐr6   c               ó(   € V ^8„  d   QhRRRRRRRR/# ©	r.   rt  rZ   r±  r0   r³  rÅ  r1   rd   r2   )r3   s   "r4   r5   rˆ   g  s)   € ÷ (ñ (¨Cð (¸ð (Ètð (ÐX\ñ (r6   c           	   ƒ  	ó  "  € Vw  rEpV P                  V P                  VR 4      pV'       g   R# \        RR4      pVf   R# VR8X  dg    VP                  V4      p	V	'       g   \
        P                  RV4       R# WpP                  V&   V P                  V\        R4      R	4      G Rj  x€L
  R
#  \        V4      p
TP                  T\        TP                  R4      ;'       g    \        T
^,           4      4      4      '       g   \
        P                  RT4       R# R
#   \         d    \
        P                  RT4       Rp	 Léi ; i LŸ  \         d)    \
        P                  RT4       YpP                  T&    R# i ; i5i)uj   [whatsapp_cloud] clarify tap with no matching state (clarify_id=%s) â€” likely stale; falling back to textFztools.clarify_gatewayzL[whatsapp_cloud] clarify resolver unavailable; falling back to text dispatchNÚotherz1[whatsapp_cloud] mark_awaiting_text failed for %sz\[whatsapp_cloud] clarify 'Other' tap but entry missing (clarify_id=%s); falling back to textz%platform.whatsapp.clarify_type_answerz,[whatsapp_cloud] clarify other-prompt failedTz3[whatsapp_cloud] clarify tap had non-int choice: %rrE   u]   [whatsapp_cloud] clarify resolver reported no waiter (clarify_id=%s) â€” falling back to text)rÁ  rÎ   r}   Úmark_awaiting_textr=  r{   r>  r.  r¹  r   rL   rU   r|   Úresolve_gateway_clarifyrZ   r;   )rÓ   rt  r±  r³  rÖ   r¸  r½  r”  Úclarify_gatewayÚflippedrƒ  s   &&&&       r4   Ú_handle_clarify_tapÚ(WhatsAppCloudAdapter._handle_clarify_tapg  sŒ  é € Ø %Ñˆ�vØ×)Ñ)Ø×Ñ Øxó
ˆ÷ ÙÜ*Ø#Ð%só
ˆð Ò"ÙØ�WÔð Ø)×<Ñ<¸ZÓH�÷ ä—‘Ðzð  }Gô  HÙà.9×Ñ 
Ñ+Ø×)Ñ)¨"¬aÐ0WÓ.Xð  [Ió  J÷  Jð  JÙð	Ü�f“+ˆCð ×6Ñ6°zÄ3ÀuÇyÁyÐQXÓGY×GiÐGiÔ]`ÐadÐghÕahÓ]iÓCj×kÒkÜ�K‰KÐwð  zDô  EÙÙøô+ ô  Ü× Ñ Ð!TÐV`ÔaØ’ð úñ Jøô ô 	Ü�N‰NÐPÐRXÔYØ.9×Ñ 
Ñ+Úð	üsm   ‚AE?Á	D ÁE?Á"AE?Â'EÂ(E?Â/E	 Â:(E?Ã# E?ÄE?Ä#EÅE?ÅEÅE?Å	/E<Å8E?Å;E<Å<E?c               ó(   € V ^8„  d   QhRRRRRRRR/# rÄ  r2   )r3   s   "r4   r5   rˆ   ‘  s*   € ÷ ñ ¨Sð ¸ð ÐPTð ÐY]ñ r6   c              ƒ  	ód  "  € Vw  rEpV P                  V P                  VR VR4      pV'       g   R# \        RR4      pVf   R# VP                  Wv4      p	V	'       d   \	        VR8X  d   RMR4      p
M!\
        P                  RV4       \	        R	4      p
V P                  WR
4      G Rj  x€L
  R#  L5i)ul   [whatsapp_cloud] approval tap with no matching state (approval_id=%s) â€” likely stale; falling back to textÚapproveFztools.approvalz.[whatsapp_cloud] approval resolver unavailableNzplatform.whatsapp.approvedzplatform.whatsapp.deniedub   [whatsapp_cloud] approval resolver reported no waiter (session_key=%s) â€” likely already resolvedz"platform.whatsapp.approval_expiredz([whatsapp_cloud] approval confirm failedT)rÏ  Údeny)rÁ  rÏ   r}   Úresolve_gateway_approvalr   r{   r.  r¹  )rÓ   rt  r±  r³  rÖ   rÜ  r½  r”  ÚapprovalÚcountÚconfirm_texts   &&&&       r4   Ú_handle_approval_tapÚ)WhatsAppCloudAdapter._handle_approval_tap‘  s¾   é € Ø!&Ñˆ˜Ø×)Ñ)Ø×%Ñ% {ØzØÐ'ó
ˆ÷
 ÙÜ#Ð$4Ð6fÓgˆØÒÙØ×1Ñ1°+ÓFˆ÷ Ü¸VÀyÔ=PÑ9ÐVpÓq‰Lä�K‰KÐ|ð  Jô  KÜÐAÓBˆLØ×%Ñ% bÐ8bÓc×cÐcÙñ 	dùs   ‚B%B0Â'B.Â(B0c               ó(   € V ^8„  d   QhRRRRRRRR/# rÄ  r2   )r3   s   "r4   r5   rˆ   ¨  s*   € ÷ ñ °#ð ¸nð ÐUYð Ð^bñ r6   c              ƒ  	ó^  "  € Vw  rEpV P                  V P                  VR VR4      pV'       g   R# \        RR4      pVf   R#  VP                  WvV4      G Rj  x€L
 p	T	'       d   T P                  YR4      G Rj  x€L
  R#  L(  \         d    \
        P                  R4        R# i ; i L/5i)	uZ   [whatsapp_cloud] slash_confirm tap with no matching state (confirm_id=%s) â€” likely staleFztools.slash_confirmz3[whatsapp_cloud] slash_confirm resolver unavailableNz-[whatsapp_cloud] slash_confirm.resolve failedTz+[whatsapp_cloud] slash_confirm reply failed)ÚonceÚalwaysÚcancel)rÁ  rÐ   r}   Úresolver=  r{   r>  r¹  )
rÓ   rt  r±  r³  rÖ   r½  rà  r”  Úslash_confirmÚresult_texts
   &&&&      r4   Ú_handle_slash_confirm_tapÚ.WhatsAppCloudAdapter._handle_slash_confirm_tap¨  s¸   é € Ø %Ñˆ�:Ø×)Ñ)Ø×%Ñ% zØhØÐ0ó
ˆ÷
 ÙÜ(Ð)>Ð@uÓvˆØÒ Ùð	Ø -× 5Ñ 5°kÈvÓ V×VˆK÷ Ø×)Ñ)¨"Ð;hÓi×iÐiÙñ WøÜô 	Ü×ÑÐLÔMÚð	úñ jùsN   ‚AB-ÁB ÁBÁB ÁB-Á&B-Á;B+Á<B-ÂB Â B(Â$B-Â'B(Â(B-rÂ  rØ  zsc:c               ó(   € V ^8„  d   QhRRRRRRRR/# )r.   Úmsg_type_strrZ   r/   r0   r?   r1   z tuple[list[str], list[str], str]r2   )r3   s   "r4   r5   rˆ   ¿  s4   € ÷ [ñ [¸ð [È>ð [Ðadð [ð  jJñ [r6   c              ƒ  óÔ  "  € VP                  V4      ;'       g    / p\        VP                  R4      ;'       g    R4      P                  4       \        VP                  R4      ;'       g    R4      P                  4       reV'       g   . . V3# V P                  V\	        V4      R7      G Rj  x€L
 w  rxV'       d   \
        P                  RW4       M\
        P                  RW4       VR8X  d3   \        VP                  R	4      ;'       g    R4      P                  4       MRp	T;'       g    V	'       d   R
V	 R2MTpV'       g   . . V3# V.T;'       g    T;'       g    R.V3#  L¸5i)zTDownload inbound media by ``media_id``; returns ``(media_urls, media_types, body)``.rd  rg   rí  )rG  Nz,[whatsapp_cloud] cached inbound %s media: %sum   [whatsapp_cloud] failed to download inbound %s (id=%s) â€” agent will see message metadata but not the binaryr   r  z[Document: Ú]r"   )r;   rZ   rj   rW  ra   r{   r.  r|   )
rÓ   râ  r/   r?   r±  r   Úinbound_mimeÚ
local_pathÚdl_mimeÚfnames
   &&&&      r4   Ú_collect_inbound_mediaÚ+WhatsAppCloudAdapter._collect_inbound_media¿  s:  é € à—‘ Ó-×3Ð3°ˆÜ!$ U§Y¡Y¨t£_×%:Ð%:¸Ó!;×!AÑ!AÓ!CÄSÈÏÉÐS^ÓI_×IeÐIeÐceÓEf×ElÑElÓEn�,ßØ�r˜4�<ÐØ$(×$AÑ$AÀ(ÔUbÐcoÓUpÐ$AÓ$q×qÑˆ
ßÜ�K‰KÐFÈÕaä�N‰NØØôð =IÈJÔ<V”�E—I‘I˜jÓ)×/Ð/¨RÓ0×6Ñ6Ô8Ð\^ˆØ×BÐB·%˜+ e W¨AÑ.¸TˆßØ�r˜4�<ÐØˆ|˜g×SÐS¨×SÐSÐ9SÐTÐVZÐZÐZñ rùsB   ‚8E(»0E(Á,AE(Â-E&Â.AE(ÄE(Ä-E(Ä6E(ÅE(Å	E(Å E(c               ó$   € V ^8„  d   QhRRRRRR/# )r.   Ú
media_urlsz	list[str]r?   rZ   r1   ztuple[str, list[bool]]r2   )r3   s   "r4   r5   rˆ   Ô  s"   € ÷ ñ ¨)ð ¸3ð ÐCYñ r6   c           	     ó  € R.\        V 4      ,          p\        \        \        V 4      4       F¥  w  r4VP                  P                  4       \        9  d   K*   VP                  4       P                  pV\        8”  d   \        P                  RWE\        4       Km  RVP                   RVP                  RRR7       2pV'       d   V RV 2MTpR	W#&   K§  	  W3#   \         d    \        P                  R
T4        KÐ  i ; i)u    Prepend text-readable document contents (â‰¤100KB) to the body; returns
``(body, media_text_inlined)`` with one flag per ``media_urls`` entry (True = injected).Fz?[whatsapp_cloud] skipping text injection for %s (%d bytes > %d)z[Content of z]:
z	utf-8-sigrò   )ÚencodingÚerrorsr»  Tz1[whatsapp_cloud] failed to read document text: %s)rT   r}  Úmapr   Úsuffixrk   Ú_TEXT_INJECT_EXTSÚstatÚst_sizeÚ_MAX_TEXT_INJECT_BYTESr{   r.  ru   Ú	read_textr4  r>  )rì  r?   Úinlinedr¾  ÚdocÚ	file_sizeÚ	injections   &&     r4   Ú_inject_document_textÚ*WhatsAppCloudAdapter._inject_document_textÓ  sò   € ð �'œC 
›OÕ+ˆÜ¤¤D¨*Ó 5Ö6‰FˆAØ�z‰z×ÑÓ!Ô):Ô:Ùð	[ØŸH™H›J×.Ñ.�	ØÔ5Ô5Ü—K‘KÐ aÐcfô  tJô  KÙØ*¨3¯8©8¨*°D¸¿¹ÐP[Ðdm¸Ó9nÐ8oÐp�	ß37˜)˜ D¨¨Ñ/¸Y�Ø!�“
ñ 7ð ˆ}Ðøô ô [Ü× Ñ Ð!TÐVY×Zð[ús   ÁA CÂ*CÃCÃ!C>Ã=C>c               ó(   € V ^8„  d   QhRRRRRRRR/# )r.   r/   r0   rœ  r%   ro   r1   zOptional[MessageEvent]r2   )r3   s   "r4   r5   rˆ   ç  s2   € ÷ B
ñ B
Ø)ðB
Ø=KðB
ØWeðB
à	ñB
r6   c              ƒ  ó®  "  € \        VP                  R4      ;'       g    R4      P                  4       pV\        9   d(   \        P                  RWAP                  R4      4       R# VR8X  d"   V P                  W4      G Rj  x€L
 '       d   R# \        P                  V4      pV'       d   \        V! V4      ;'       g    R4      MRp\        VP                  R4      ;'       g    R4      P                  4       ;rxVP                  VR4      p	VP                  R	4      '       d8   \        P                  R
VP                  R	4      VP                  R4      4       R# V P                  RVRVRRRV/4      '       g   R# . . . rËp
V\        9   d@   V P                  WAV4      G Rj  x€L
 w  r«pVR8X  d   V
'       d   V P                  W¦4      w  rlVP                  R4      ;'       g    / p\        VP                  R4      ;'       g    R4      P                  4       ;'       g    RpV'       d   \        P                  ! W~4      MRp\        VP                  R4      ;'       g    R4      P                  4       p\        VP                  R4      ;'       g    R4      P                  4       p\!        T;'       d    T;'       d    T4      ;'       d    VV8H  p\        VP                  R4      ;'       g    R4      ;'       g    RpV'       d’   V'       dŠ   \#        V P$                  VV\&        4       V'       d!   \        P(                  ! VVV4      G Rj  x€L
  V\        9   d;   V
'       d3   \        P*                  ! VV\-        \/        W«4      4      4      G Rj  x€L
  V'       dL   \        P0                  ! W~4       F1  w  ppVV
9  g   K  V
P3                  V4       VP3                  V4       K3  	  \5        T\6        P                  V\8        P:                  4      T P=                  Yy;'       g    TRY‰;'       g    RR7      VVVVVW«VR7      #  ELÈ EL« EL  L½5i)zMConvert a Cloud-API message object into a MessageEvent, or None if gated out.rZ  r(   z<[whatsapp_cloud] skipping contentless %s envelope (wamid=%s)rd  Nr*   rg   r¦  Úchatu¨   [whatsapp_cloud] received group-shaped message (chat=%s, wamid=%s) â€” group support is not yet implemented; dropping. Use the Baileys whatsapp adapter for group chats.ÚchatIdÚsenderIdÚisGroupFr?   r   ru  Údisplay_phone_numberrç  )rk  Ú	chat_nameÚ	chat_typeÚuser_idÚ	user_name)r(   Úmessage_typer  r/   rf  rr   Úreply_to_textÚreply_to_is_own_messagerì  Úmedia_typesÚmedia_text_inlined)rZ   r;   rk   Ú_CONTENTLESS_KINDSr{   rŒ  rµ  Ú_BODY_BY_KINDrj   r|   Ú_should_process_messageÚ_INBOUND_MEDIA_KINDSré  rû  r   Úlookuprd   r   rÍ   r–  r€  r  rÅ  ÚzipÚlookup_mediarÊ  r   Ú_MESSAGE_TYPE_BY_KINDr   ÚTEXTÚbuild_source)rÓ   r/   rœ  ro   râ  Úextractr?   rk  r²  Úsender_namerì  r  r  ru  Úreply_to_idr	  Úquoted_fromÚ
our_numberÚreply_to_is_ownr�  rÛ   rY   s   &&&&                  r4   r   Ú4WhatsAppCloudAdapter._build_message_event_from_cloudç  s�  é € ô ˜;Ÿ?™?¨6Ó2×<Ð<°fÓ=×CÑCÓEˆð Ô-Ô-Ü�L‰LÐWÐYe×gvÑgvÐw{Óg|Ô}Ùð ˜=Ô(°4×3SÑ3SÐT_Ó3r×-rÖ-rÙÜ×#Ñ# LÓ1ˆß29Œs‘7˜;Ó'×-Ð-¨2Ô.¸rˆÜ! +§/¡/°&Ó"9×"?Ð"?¸RÓ@×FÑFÓHÐHˆØ&×*Ñ*¨9°bÓ9ˆð �?‰?˜6×"Ò"Ü�N‰Nð[à—‘ Ó'¨¯©¸Ó)>ôñ
 Ø×+Ñ+¨X°wÀ
ÈIÐW`ÐbgÐioÐquÐ,v×wÒwÙØ68¸"¸bÐ!3ˆ
ØÔ/Ô/Ø26×2MÑ2MÈlÐimÓ2n×,nÑ)ˆJ TØ˜zÔ)¯jØ+/×+EÑ+EÀjÓ+WÑ(�ð —/‘/ )Ó,×2Ð2°ˆÜ˜'Ÿ+™+ dÓ+×1Ð1¨rÓ2×8Ñ8Ó:×BÐB¸dˆßHSœ×.Ò.¨wÔDÐY]ˆä˜'Ÿ+™+ fÓ-×3Ð3°Ó4×:Ñ:Ó<ˆÜ˜Ÿ™Ð&<Ó=×CÐCÀÓD×JÑJÓLˆ
Ü˜{×IÐI¨{×IÐI¸zÓJ×hÐhÈ{Ð^hÑOhˆÜ�K—O‘O DÓ)×/Ð/¨RÓ0×8Ð8°Dˆß—Wä˜×8Ñ8¸'À5ÔJfÔgßÜ%×2Ò2°7¸EÀ4ÓH×HÐHØÔ3Ô3¿
Ü%×8Ò8¸À%ÌÌcÐR\ÓNjÓIkÓl×lÐlßÜ-×:Ò:¸7ÖP‘
��dØ˜zÖ)Ø×%Ñ% dÔ+Ø×&Ñ& tÖ,ñ Qô ØÔ$9×$=Ñ$=¸lÌK×L\ÑL\Ó$]Ø×$Ñ$Ø×+AÐ+A¸'ÈTØ!×-@Ð-@¸Dð %ó ð $°È;Ø'ÀØ!ÐOaô	
ð 		
ò[ .sò& -oò$ IálùsÚ   ‚B QÂQ
Â	QÂQÂ,QÃ %QÃ&BQÅ;'QÆ"QÆ#QÆ9*QÇ$QÈQÈ 
QÈ+4QÉ 1QÊ"QÊ5	QÊ?QË"QË0QË>
QÌ	QÌ?QÍQÍQÍ(-QÎQÎQÎ" QÏA"QÐ*QÐ6QÑQÑQÑQ)rÊ   r®   rÁ   r¼   r¯   r°   rÎ   rÂ   rÉ   rÏ   rÅ   rÃ   rº   rÒ   rÍ   rÇ   r­   rË   r½   rÑ   rÈ   rÐ   r²   r±   rÌ   r´   r¹   r¶   r2   rM  r¨  )é   )i   )NNN)rg   r2   )Fr[  Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r…   Ú__annotations__Úsplits_long_messagesr«   Ústaticmethodr·   rå   rì   rô   r¿   r  r  r  r4  rE  rN  r]  rh  rv  r…  rŽ  r˜  r   r¤  r¬  Úclassmethodr³  rÍ  ÚpropertyrÒ  Ú_EA_CODE_CLOSEÚ_EA_CMD_BUDGETrÝ  rã  rè  r  r	  r  r  r   r&  r+  r7  r1  rE  rW  r(  r)  r+  rv  rŠ  rx  r™  rµ  r¹  rÁ  rË  rÕ  rß  r¯  ré  rû  r   Ú__static_attributes__Ú__classcell__)rØ   s   @r4   r„   r„   ¥   s¤  ø‡ ñWð #'Ð˜4Ó&àÐ÷00ð 00ðf ô9ó ð9õhðY°÷ Yõað ôUó ðU÷eð eõ
÷Sð Sð
&°E÷ &õP
"ð ô
Ió ð
IðÐtv÷ õ Sð ôó ð÷D÷8lõ4ð  öQó ðQð
 öIó ðIð
 ôcó ðcð ôtó ðt÷#zðJ ô2ó ð2ð !€NØ€Nõ	v÷
@õ/÷
Xð2
ØJNð
à$(ð
àCGð
ð #'ð
ð CG÷
ð.ØVZðà"&ðàBFðð $(÷÷.y÷z÷z÷
÷Oõ$yõ
ð!+ÐY]÷ !+õHõPõ (õ>]õõ%rõN[õ*Uõ*'ð öó ðõ(õTõ.ð* #Ð$7¸ÐBVÐX]Ð_xÐyÐõ[ð( ôó ð÷&B
ó B
r6   r„   c               ó   € V ^8„  d   QhRR/# rc   r2   )r3   s   "r4   r5   r5   0  s   € ÷ ^ñ ^˜Tñ ^r6   c                ó  a€ V e   \        V RR4      ;'       g    / M/ pVP                  R4      '       d   VP                  R4      '       d   R# ^ RIHo \        ;QJ d    V3R lR 4       F  '       d   K   R# 	  R# ! V3R lR 4       4      # )	z·Phone-number id + access token, from ``PlatformConfig.extra`` (YAML / env seeding) or the
scope-aware env reader (``hermes_cli.gateway.get_env_value`` so setup-status patches see it).NrŽ   rŸ   r    Tc              3  óv   <"  € T F.  pSP                  V4      ;'       g    R P                  4       x € K0  	  R# 5ir‹   )Úget_env_valuerj   )rŒ   ru   Úgateway_mods   & €r4   r�   Ú _is_connected.<locals>.<genexpr>7  s8   øé € ð ^Ù\�4ð ×)Ñ)¨$Ó/×5Ð5°2×<Ñ<×>Ð>Û\ùs   ƒ9 9F)ÚWHATSAPP_CLOUD_PHONE_NUMBER_IDÚWHATSAPP_CLOUD_ACCESS_TOKEN)r<  r;   Úhermes_cli.gatewayÚgatewayÚall)r‡   rŽ   r0  s   & @r4   Ú_is_connectedr7  0  sŠ   ø€ ð 7=Ò6HŒW�V˜W dÓ+×1Ð1¨røÈb€EØ‡y�yÐ"×#Ò#¨¯	©	°.×(AÒ(AÙÝ,ß‹3ô ^Ù\ó^�3Œ3ð ^Š3ð ^ˆ3ô ^Ù\ó^ó ^ð ^r6   c               ó   € V ^8„  d   QhRR/# r7  r2   )r3   s   "r4   r5   r5   ;  s   € ÷ ñ ˜Dñ r6   c                 ó    € ^RI Hp  V ! 4        R# )zO``hermes gateway setup`` entry: the same wizard ``hermes whatsapp-cloud`` runs.©Úrun_whatsapp_cloud_setupN)Úsetup_wizardr;  r:  s    r4   Ú_interactive_setupr=  ;  s   € å6ÙÖr6   uÿ  You are on WhatsApp (Meta Business Cloud API). Standard markdown auto-converts to WhatsApp syntax â€” write markdown freely. No tables â€” use bullets or labeled lines. You can send files natively: write MEDIA:/absolute/path/to/file in your response. Images (.jpg, .png) send as photos, videos (.mp4) inline, audio as voice/audio, other files as documents; ![alt](url) works. NOTE: Meta refuses free-form replies when the user hasn't messaged in 24h (error 131047) â€” relevant only for delayed/scheduled sends.c               ó   € V ^8„  d   QhRR/# r7  r2   )r3   s   "r4   r5   r5   L  s   € ÷ ñ �Tñ r6   c           	     ó$  € ^RI Hp V P                  ! R$/ RRbRRbR\        bRRbR	R
bRRbR\        bR\
        bR\        RR4      bRRR.bRRbR\        bRRbRRbRRbR\        bRR bR!VP                  bR"VP                  bVP                  B  R## )%u‘  Plugin entry point â€” called by the Hermes plugin system.

No ``validate_config``: an unconfigured adapter still reaches ``connect()``, which records the
``whatsapp_cloud_unconfigured`` fatal error (same outcome as the former core wiring). No
``standalone_sender_fn`` / ``max_message_length``: out-of-process ``send_message`` had no
WhatsApp Cloud sender in core either, and ``send()`` chunks itself.)Úgateway_envru   Úwhatsapp_cloudÚlabelzWhatsApp Business (Cloud)Úadapter_factoryÚdashboard_labelzWhatsApp Cloud APIÚdashboard_descriptionzBUse Hermes via Meta's hosted WhatsApp Cloud API (no local bridge).Údocs_urlzNhttps://hermes-agent.nousresearch.com/docs/user-guide/messaging/whatsapp-cloudÚcheck_fnÚis_connectedÚconfig_connected_fnrŸ   r    Úrequired_envr2  r3  Úinstall_hintu0   aiohttp/httpx missing â€” reinstall hermes-agentÚsetup_fnÚcron_deliver_env_varÚWHATSAPP_CLOUD_HOME_CHANNELÚemojiu   ðŸ“±Úallow_update_commandFÚplatform_hintÚdisplay_tierÚlowÚenv_overridesÚenv_enable_credentialsNr2   )rg   r@  Úregister_platformr„   r‚   r7  r   r=  Ú_PLATFORM_HINTÚENV_OVERRIDESÚENV_ENABLE_CREDENTIALSÚAUTHZ)Úctxr@  s   & r4   Úregisterr\  L  sø   € õ Ø×Òò ÙðÙ%@ðÝRfðá,ðñ cðñ bð	õ
 3ðõ
 BOðô 3Ð3DÀnÔUðð 7Ð8UÑVðñ Hðõ Seðñ ;ðñ CIðñ `eðõ %ðñ ðð "×/Ò/ðð  +×AÒAÀ[×EVÑEVôr6   i  0 i  P i   i � i  @>   r   r   r   r'   r    r   >   ÚsystemÚunknownÚreactionÚunsupported>   ú.jsú.mdú.pyú.tsú.cssú.csvú.logú.txtú.xmlú.ymlú.htmlú.jsonú.yaml)zhttp://zhttps://)gÚ__conditional_annotations__r"  Ú
__future__r   rQ   r2  r�  ro  rx   rK  r–  rú  rõ  rû   ÚshutilrÙ  Úcollectionsr   Úpathlibr   Útypingr   r   r   Úaiohttpr   r€   rz   r"  r�   Úgateway.configr	   r
   Úgateway.platforms._sharedr   Ú
agent.i18nr   Úgateway.platforms.baser   r   r   r   Ú$gateway.platforms.base_exec_approvalr   Úgateway.platforms.helpersr   Úgateway.platforms.eventr   r   Ú!gateway.platforms.whatsapp_commonr   r   Ú%gateway.platforms.access_policy_mixinr   rl   Úgateway.platforms.media_cacher   r5  r   Úhermes_constantsr   Ú	getLoggerr[  r{   r»   r³   rµ   r¸   rã   r%  r‰  r–  rø  rü  Úwhichr>  r&   r#  r  r  rò  rõ  r  ÚPHOTOÚVIDEOÚVOICEÚDOCUMENTr  r  r=   r  rW   ra   rm   rs   r}   rO  r‚   r„   r7  r=  rW  r\  )rl  rn  s   0@r4   Ú<module>r†     sË  øðôRõ #ã Û Û Û Û Û Û Û Û 	Û 	Û Û Ý #Ý ß &Ñ &ðÝØÐðÛØ€O÷
 4Ý <Ý ß mÓ mÝ ?Ý 1ß =ß QÝ OÝ 6Ý #Ý +à	×	Ò	˜8Ó	$€ð Ð àÐ ØÐ Ø*Ð Ø-€Ø(Ð ð Ð Ø#Ð ð
 ˆ_˜gÐ'7¸ÐBRØÐ! 9¨jðÐ ð ˆ\˜7 K°¸,ØÐ*¨I°|ð€ð �|Š|˜HÓ%€ð
 �Ð+¨V°\À6Ø�˜¨°¸fð6Ð " Nó ò
 SÐ ò FÐ Ú{Ð Ø#Ð à
ˆK×Ñ˜g {×'8Ñ'8¸'À;×CTÑCTØˆ[×Ñ ¨×):Ñ):¸JÈ×H\ÑH\Øˆ{× Ñ  (¨K×,<Ñ,<¸mÈ[×M]ÑM]Ø�× Ñ  *¨k×.>Ñ.>ð	Ð ð )€õFð Ñ7ØÑ;ØÑ?ðñ NbÓbÑMaÀT˜$Ó?Ò?ÑMaÑbð	€õõUõ
rõ7õñ ™NÐ+KÐMcÓdÓeÐ õ1ô
D
Ð0Ð2Eô D
õV^õðKð ÷øðY! ô ØÐØ
ƒCðûð ô Ø€OØƒEðüòb cs*   ÁH( ÁH: Ç IÈ(H7È6H7È:I	ÉI	