+
    kHàjŠL ã                  ó¼  € R t ^ RIH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HtHtHt ^ RIHt ^ RIHtHtHtHtHtHtHt ^ RIHt  ^ RItRt ^ RItRt ^ R
I!H"t"H#t# ^ RI$H%t%H&t&H't'H(t(H)t)H*t* ^ RI+H,t,H-t- ^ RI.H/t/ ^ RI.H0t0H1t1H2t2 ^ RI3H4t4 ^ RI5H6t6 ]Pn                  ! ]84      t9 ! R R]:4      t;^RI<H=t=H>t>H?t?H@t@HAtAHBtBHCtCHDtDHEtEHFtFHGtGHHtHHItIHJtJHKtKHLtLHMtMHNtNHOtOHPtPHQtQHRtR ^RISHTtUHVtV ^RIWHXtXHYtYHZtZ ^RI[H\t\H]t]H^t^H_t_H`t`HataHbtbHctc ^ RIdHetf R R ltgR!thRRRRRR/ti0 R"mtj ! R R ]4]&4      tkR#   ] d    R	tRt Lëi ; i  ] d    R	t Rt Lõi ; i)#a   QQ Bot platform adapter (Official QQ Bot API v2): WebSocket gateway for inbound
events, REST (``api.sgroup.qq.com``) for outbound messages and media uploads.

config.yaml ``platforms.qq.extra``: app_id / client_secret (or QQ_APP_ID /
QQ_CLIENT_SECRET), markdown_support, dm_policy + allow_from, group_policy +
group_allow_from (open | allowlist | disabled | pairing), and optional ``stt``
{provider, baseUrl, apiKey, model} (or QQ_STT_* env vars). Voice transcription
tries QQ's free ``asr_refer_text`` first, then the configured STT provider.
)Úannotations)Úinstall_hintN)ÚdatetimeÚtimezoneÚUTC)ÚPath)ÚAnyÚ	AwaitableÚCallableÚDictÚListÚOptionalÚTuple)ÚurlparseTF)ÚPlatformÚPlatformConfig)Úgateway_trust_envÚBasePlatformAdapterÚExecApprovalPromptÚ
SendResultÚcache_document_from_bytes_asyncÚcache_image_from_bytes_async)ÚMessageEventÚMessageType)Ústrip_markdown)ÚMessageDeduplicatorÚcancel_taskÚplatform_http_client)ÚOwnAccessPolicyMixin)Úext_for_mimec                  ó0   a € ] tR t^7tRtRV 3R lltRtV ;t# )ÚQQCloseErrorzRRaised when the QQ WebSocket closes; carries code + reason for the reconnect loop.c                	óÄ   <€ V'       d   \        V4      MR V n        V'       d   \        V4      MRV n        \        SV `  RV P                   RV P                   R24       R # )NÚ zWebSocket closed (code=z	, reason=Ú))ÚintÚcodeÚstrÚreasonÚsuperÚ__init__)Úselfr&   r(   Ú	__class__s   &&&€ÚD/home/ubuntu/.hermes/hermes-agent/plugins/platforms/qqbot/adapter.pyr*   ÚQQCloseError.__init__:   sG   ø€ ß!%”C˜”I¨4ˆŒ	ß%+”c˜&”k°ˆŒÜ‰ÑÐ2°4·9±9°+¸YÀtÇ{Á{ÀmÐSTÐUÖVó    )r&   r(   ©r#   )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r*   Ú__static_attributes__Ú__classcell__©r,   s   @r-   r!   r!   7   s   ø† Ù\÷Wõ Wr/   r!   )ÚAPI_BASEÚ	TOKEN_URLÚGATEWAY_URL_PATHÚDEFAULT_API_TIMEOUTÚFILE_UPLOAD_TIMEOUTÚCONNECT_TIMEOUT_SECONDSÚRECONNECT_BACKOFFÚMAX_RECONNECT_ATTEMPTSÚRATE_LIMIT_DELAYÚQUICK_DISCONNECT_THRESHOLDÚMAX_QUICK_DISCONNECT_COUNTÚMAX_MESSAGE_LENGTHÚDEDUP_WINDOW_SECONDSÚDEDUP_MAX_SIZEÚMSG_TYPE_TEXTÚMSG_TYPE_MARKDOWNÚMSG_TYPE_MEDIAÚMSG_TYPE_INPUT_NOTIFYÚMEDIA_TYPE_IMAGEÚMEDIA_TYPE_VIDEOÚMEDIA_TYPE_VOICEÚMEDIA_TYPE_FILE)Úcoerce_listÚbuild_user_agent)ÚChunkedUploaderÚUploadDailyLimitExceededErrorÚUploadFileTooLargeError)ÚApprovalRequestÚInlineKeyboardÚInteractionEventÚbuild_approval_keyboardÚbuild_update_prompt_keyboardÚparse_approval_button_dataÚparse_interaction_eventÚparse_update_prompt_button_data)Úget_scoped_secretc               ó   € V ^8„  d   QhRR/# ©é   ÚreturnÚbool© )Úformats   "r-   Ú__annotate__rd   P   s   € ÷ 1ñ 1˜tñ 1r/   c                 ó*   € \         ;'       d    \        # ©N)ÚAIOHTTP_AVAILABLEÚHTTPX_AVAILABLErb   r/   r-   Úcheck_qq_requirementsri   P   s   € Ü×0Ð0¤Ð0r/   Úzaiz+https://open.bigmodel.cn/api/coding/paas/v4Úopenaizhttps://api.openai.com/v1Úglmc                  ób  a € ] tR t^dtRtRt]tRt^<t^2t	RRRRRR	R
RRRRRRRRRRR/	t
RR0]! ]! RR4      4      ,          t]R R l4       tR R ltR R lt]R R  l4       tR! V 3R" llt]R# R$ l4       tR%R/R& R' lltR( R) ltR* R+ ltR, R- ltR. R/ ltR0 R1 ltR2 R3 ltR4 R5 ltR6R/R7 R8 lltR9 R: ltR; R< ltR= R> lt R? R@ lt!RA RB lt"RC RD lt#RE RF lt$RG RH lt%]&RI 4       t'RJ RK lt(RL RM lt)]&RN RO l4       t*]&RP RQ l4       t+RR V 3RS llt,RT RU lt-RV RW lt.RX RY lt/ERRZ R[ llt0R\R]R^R_R`R`/t1]&Ra Rb l4       t2Rc Rd lt3Re Rf lt4Rg Rh lt5]&ERRi Rj ll4       t6Rk Rl lt7Rm Rn lt8Ro Rp lt9Rq Rr lt:RsRtRuRvRwRxRyRxRzR{/t;]&R| R} l4       t<R~R/R R€ llt=R� R‚ lt>]&Rƒ R„ l4       t?]&R… R† l4       t@R‡ Rˆ ltA]&R‰ RŠ l4       tBERR‹ RŒ lltC]&R� RŽ l4       tDR� R� ltER‘R’R“R’/R” R• lltF]&R– R— l4       tG]&R˜ R™ l4       tH]&Rš R› l4       tI]JRœ R� l4       tKRž RŸ ltLERtM]JR  R¡ l4       tN]JR¢ R£ l4       tOR¤ R¥ ltPR¦ R§ ltQR¨ R© ltRRª R« ltSR¬ R­ ltTR® R¯ ltUR° R± ltVR’]W3R² R³ lltXR´ Rµ ltYERR¶ R· lltZR¸t[R¹t\Rº R» lt]]R¼ R½ l4       t^R¾ R¿ lt_ER	RÀ RÁ llt`ER
taERRÂ RÃ lltb]&RÄ RÅ l4       tc]JRÆ RÇ l4       tdRÈ RÉ lteER	RÊ RË lltfER	RÌ RÍ lltgER	RÎ RÏ llthRÐRÑRÒRÓRÔRÕ/tiRÖR/R× RØ lltjERRÙ RÚ lltkERRÛ RÜ lltlERRÝ RÞ lltmRßtnRà Rá ltoERRâ Rã lltpERRä Rå lltqERRæ Rç lltrER	Rè Ré lltsER	Rê Rë llttER	Rì Rí lltuERRî Rï lltvERRð Rñ lltwRò Ró ltxERRô Rõ lltyRö R÷ ltzRø Rù lt{]&Rú Rû l4       t|Rü Rý lt}]&Rþ Rÿ l4       t~ER  ER ltER ER lt€ERt�V ;t‚# (  Ú	QQAdapterzJQQ Bot adapter backed by the official QQ Bot WebSocket Gateway + REST API.FÚQQi¡  zinvalid opcodei¢  zinvalid payloadiª  zinvalid shardi«  zsharding requiredi¬  zinvalid API versioni­  zinvalid intenti®  zintent not authorizedi2  zoffline/sandbox-onlyi3  Úbannedi¦  i§  i$  c               ó   € V ^8„  d   QhRR/# ©r_   r`   r'   rb   )rc   s   "r-   rd   ÚQQAdapter.__annotate__y   s   € ÷ 8ñ 8˜#ñ 8r/   c                ó:   € \        V RR4      pV'       d   RV 2# R# )z>Log prefix including app_id for multi-instance disambiguation.Ú_app_idNzQQBot:ÚQQBot)Úgetattr)r+   Úapp_ids   & r-   Ú_log_tagÚQQAdapter._log_tagx   s&   € ô ˜˜y¨$Ó/ˆß$*�˜�xÐ Ð7°Ð7r/   c               ó    € V ^8„  d   QhRRRR/# )r_   r(   r'   r`   ÚNonerb   )rc   s   "r-   rd   rs   ~   s   € ÷ (ñ ( Cð (¨Dñ (r/   c                	óà   € V P                   P                  4        F5  pVP                  4       '       d   K  VP                  \	        V4      4       K7  	  V P                   P                  4        R # rf   )Ú_pending_responsesÚvaluesÚdoneÚset_exceptionÚRuntimeErrorÚclear)r+   r(   Úfuts   && r-   Ú_fail_pendingÚQQAdapter._fail_pending~   sM   € Ø×*Ñ*×1Ñ1Ö3ˆCØ—8‘8—:”:Ø×!Ñ!¤,¨vÓ"6Ö7ñ 4ð 	×Ñ×%Ñ%Ö'r/   c               ó   € V ^8„  d   QhRR/# ©r_   r`   r|   rb   )rc   s   "r-   rd   rs   „   s   € ÷ `ñ `¨dñ `r/   c                óX   € V P                   '       d   R# V P                  RRRRR7       R# )z‹Mark QQ WS down without stopping the reconnect loop (base's _running
doubles as lifecycle flag; the listener must survive transient drops).NÚdisconnected)Úplatform_stateÚ
error_codeÚerror_message)Úhas_fatal_errorÚ_write_runtime_status_safe©r+   s   &r-   Ú_mark_transport_disconnectedÚ&QQAdapter._mark_transport_disconnected„   s1   € ð ××ÐÙØ×'Ñ'Ø¨>ÀdÐZ^ð 	(ö 	`r/   c               ó   € V ^8„  d   QhRR/# r^   rb   )rc   s   "r-   rd   rs   �   s   € ÷ Hñ H˜dñ Hr/   c                óš   € \        V P                  ;'       d0    V P                  ;'       d    V P                  P                  '       * 4      # )z;Return True only when the QQ WebSocket transport is usable.)ra   Ú_runningÚ_wsÚclosedr�   s   &r-   Úis_connectedÚQQAdapter.is_connectedŒ   s2   € ô �D—M‘M×FÐF d§h¡h×FÐF°t·x±x·±Ô3FÓGÐGr/   c               ó   € V ^8„  d   QhRR/# )r_   Úconfigr   rb   )rc   s   "r-   rd   rs   ‘   s   € ÷ !0ñ !0˜~ñ !0r/   c                	óÒ  <€ \         SV `  V\        P                  4       VP                  ;'       g    / p\        VP                  R 4      ;'       g    \        RR4      4      P                  4       V n	        \        VP                  R4      ;'       g    \        RR4      4      P                  4       V n
        \        VP                  RR4      4      V n        \        VP                  RR4      4      P                  4       P                  4       V n        \        VP                  R	4      ;'       g    VP                  R
4      4      V n        \        VP                  RR4      4      P                  4       P                  4       V n        \        VP                  R4      ;'       g    VP                  R4      4      V n        RV n        RV n        RV n        RV n        RV n        RV n        RV n        RV n        / V n        / V n        \;        \<        \>        R7      V n         / V n!        / V n"        RV n#        RV n$        \J        PL                  ! 4       V n'        V PP                  V n)        R# )rx   Ú	QQ_APP_IDr#   Úclient_secretÚQQ_CLIENT_SECRETÚmarkdown_supportTÚ	dm_policyÚpairingÚ
allow_fromÚ	allowFromÚgroup_policyÚgroup_allow_fromÚgroupAllowFromNç      >@)Úmax_sizeÚttl_secondsç        )*r)   r*   r   ÚQQBOTÚextrar'   ÚgetÚ_resolve_qq_secretÚstripru   Ú_client_secretra   Ú_markdown_supportÚlowerÚ
_dm_policyÚ_coerce_listÚ_allow_fromÚ_group_policyÚ_group_allow_fromÚ_sessionr–   Ú_http_clientÚ_listen_taskÚ_heartbeat_taskÚ_heartbeat_intervalÚ_session_idÚ	_last_seqÚ_chat_type_mapr~   r   rF   rE   Ú_dedupÚ_last_msg_idÚ_typing_sent_atÚ_access_tokenÚ_token_expires_atÚasyncioÚLockÚ_token_lockÚ_default_interaction_dispatchÚ_interaction_callback)r+   r›   r­   r,   s   && €r-   r*   ÚQQAdapter.__init__‘   sà  ø€ Ü‰Ñ˜¤§¡Ô0à—‘×"Ð" ˆÜ˜5Ÿ9™9 XÓ.×UÐUÔ2DÀ[ÐRTÓ2UÓV×\Ñ\Ó^ˆŒÜ! %§)¡)¨OÓ"<×"jÐ"jÔ@RÐSeÐgiÓ@jÓk×qÑqÓsˆÔÜ!% e§i¡iÐ0BÀDÓ&IÓ!JˆÔÜ˜eŸi™i¨°YÓ?Ó@×FÑFÓH×NÑNÓPˆŒÜ'¨¯	©	°,Ó(?×(YÐ(YÀ5Ç9Á9È[ÓCYÓZˆÔÜ  §¡¨>¸9Ó!EÓF×LÑLÓN×TÑTÓVˆÔÜ!-¨e¯i©iÐ8JÓ.K×.jÐ.jÈuÏyÉyÐYiÓOjÓ!kˆÔà9=ˆŒØ>BˆŒØ9=ˆÔØ48ˆÔØ7;ˆÔØ*.ˆÔ Ø*.ˆÔØ(,ˆŒØ.0ˆÔØ=?ˆÔÜ)´>ÔOcÔdˆŒØ,.ˆÔØ13ˆÔØ,0ˆÔØ(+ˆÔÜ"Ÿ<š<›>ˆÔð ×.Ñ.ð 	Ö"r/   c               ó   € V ^8„  d   QhRR/# rr   rb   )rc   s   "r-   rd   rs   ·   s   € ÷ ñ �cñ r/   c                	ó   € R # )rv   rb   r�   s   &r-   ÚnameÚQQAdapter.name¶   s   € ár/   Úis_reconnectc               ó    € V ^8„  d   QhRRRR/# )r_   rÐ   ra   r`   rb   )rc   s   "r-   rd   rs   ¼   s   € ÷ $ñ $¨Tð $¸dñ $r/   c             ƒ  óô  "  € \         RRR\        R4       23\        RRR3V P                  ;'       d    V P                  RRR	33 FJ  w  r#rEV'       d   K  R
V 2pV P                  W6RR7       \        P                  RV P                  We4        R# 	  V P                  RV P                  R4      '       g   R#  \        4       V n        V P                  RR7      G Rj  x€L
  \        P                  ! V P                  4       4      V n        \        P                  ! V P#                  4       4      V n        V P'                  4        \        P)                  RV P                  4       V P+                  R4       R#  L™  \,         dq   pR
T 2pT P                  RTRR7       \        P/                  RT P                  TRR7       T P1                  4       G Rj  x€L 
  T P3                  4         Rp?R# Rp?ii ; i5i)zžAuthenticate, obtain gateway URL, and open the WebSocket. ``is_reconnect``
is accepted for interface conformance only (QQBot has no server-side update queue).Úqq_missing_dependencyzaiohttp not installedz. Run: Ú	messagingzhttpx not installedz. Run: hermes pm repairÚqq_missing_credentialsz+QQ_APP_ID and QQ_CLIENT_SECRET are requiredr#   zQQ startup failed: T©Ú	retryablez	[%s] %s%sFzqqbot-appidzQQBot app ID)Úlog_urlNz[%s] ConnectedÚqq_connect_errorz[%s] %s©Úexc_info)rg   r   rh   ru   r±   Ú_set_fatal_errorÚloggerÚwarningry   Ú_acquire_platform_lockr   rº   Ú_open_gateway_wsrÆ   Úcreate_taskÚ_listen_loopr»   Ú_heartbeat_loopr¼   Ú_mark_connectedÚinfoÚ_wire_plugin_handlersÚ	ExceptionÚerrorÚ_cleanupÚ_release_platform_lock)r+   rÐ   Úokr&   ÚwhatÚhintÚmessageÚexcs   &$      r-   ÚconnectÚQQAdapter.connect¼   sÄ  é € ô Ð 7Ð9PØ”| KÓ0Ð1Ð2ð4äÐ5Ð7LÐNgÐhØ�\‰\×1Ð1˜d×1Ñ1Ð3KØ:¸Bð@ó	%AÑ ˆB�d÷ ‘2Ø/°¨vÐ6�Ø×%Ñ% d¸tÐ%ÔDÜ—‘˜{¨D¯M©M¸7ÔIÚñ%Að ×*Ñ*¨=¸$¿,¹,È×WÒWÙð	ô !5Ó 6ˆDÔà×'Ñ'°Ð'Ó5×5Ð5Ü '× 3Ò 3°D×4EÑ4EÓ4GÓ HˆDÔÜ#*×#6Ò#6°t×7KÑ7KÓ7MÓ#NˆDÔ Ø× Ñ Ô"Ü�K‰KÐ(¨$¯-©-Ô8Ø×&Ñ& tÔ,Ùñ 6øô ô 	Ø+¨C¨5Ð1ˆGØ×!Ñ!Ð"4°gÈÐ!ÔNÜ�L‰L˜ D§M¡M°7ÀTˆLÔJØ—-‘-“/×!Ñ!Ø×'Ñ'Ô)Ýûð	üs]   ‚AG8ÁA G8Â7G8Â:$E: ÃE8ÃBE: Å6G8Å8E: Å:G5ÆAG0ÇGÇG0Ç*G8Ç0G5Ç5G8c               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   â   s   € ÷ 8ñ 8 $ñ 8r/   c              ƒ  	óh  "  € R V n         V P                  4        \        V P                  4      G Rj  x€L
  \        V P                  4      G Rj  x€L
  R;V n        V n        V P                  4       G Rj  x€L
  V P                  4        \        P                  RV P                  4       R#  Ly L^ L:5i)FNz[%s] Disconnected)
r•   Ú_mark_disconnectedr   r»   r¼   ré   rê   rÝ   rå   ry   r�   s   &r-   Ú
disconnectÚQQAdapter.disconnectâ   s‰   é € ØˆŒØ×ÑÔ!Ü˜$×+Ñ+Ó,×,Ð,Ü˜$×.Ñ.Ó/×/Ð/Ø37Ð7ˆÔ˜DÔ0Ø�m‰m‹o×ÐØ×#Ñ#Ô%Ü�‰Ð'¨¯©Ö7ñ 	-Ù/áùs3   ‚0B2²B,³B2ÁB.Á%B2Á5B0Á67B2Â.B2Â0B2c               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   ì   s   € ÷ ñ  ñ r/   c              ƒ  ór  "  € V P                   '       d?   V P                   P                  '       g#   V P                   P                  4       G Rj  x€L
  RV n         V P                  '       d?   V P                  P                  '       g#   V P                  P                  4       G Rj  x€L
  RV n        R#  Ld L5i)zEClose the WebSocket + its aiohttp session (keeps _http_client alive).N)r–   r—   Úcloser¹   r�   s   &r-   Ú	_close_wsÚQQAdapter._close_wsì   st   é € à�8�8ˆ8˜DŸH™HŸOŸO˜OØ—(‘(—.‘.Ó"×"Ð"ØˆŒØ�=�=ˆ= §¡×!5×!5Ð!5Ø—-‘-×%Ñ%Ó'×'Ð'ØˆŽñ	 #ñ (ùs4   ‚.B7±B7ÁB3ÁB7Á,B7ÂB7Â%B5Â&B7Â5B7c               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   õ   s   € ÷ +ñ + ñ +r/   c              ƒ  óÞ   "  € V P                  4       G Rj  x€L
  V P                  '       d*   V P                  P                  4       G Rj  x€L
  RV n        V P                  R4       R#  LR L 5i)z@Close WebSocket, HTTP session, and client; fail pending futures.NÚDisconnected)rú   rº   Úacloser…   r�   s   &r-   ré   ÚQQAdapter._cleanupõ   sW   é € à�n‰nÓ×ÐØ××ÐØ×#Ñ#×*Ñ*Ó,×,Ð,Ø $ˆDÔØ×Ñ˜>Ö*ñ	 	á,ùs&   ‚A-–A)—A-­A-Á
A+ÁA-Á+A-c               ó$   € V ^8„  d   QhRRRRRR/# )r_   rì   r'   ÚrequestzCallable[[], Awaitable[Any]]r`   údict[str, Any]rb   )rc   s   "r-   rd   rs   ÿ   s(   € ÷ Oñ O cð OÐ4Pð OÐUcñ Or/   c              ƒ  ó¸   "  €  V! 4       G Rj  x€L
 pVP                  4        VP                  4       #  L$  \         d   p\        RT RT 24      ThRp?ii ; i5i)uG   Run an httpx request and return its JSON; any failure â†’ RuntimeError.NzFailed to get QQ Bot ú: )Úraise_for_statusÚjsonrç   r‚   )r+   rì   r  Úresprï   s   &&&  r-   Ú_fetch_jsonÚQQAdapter._fetch_jsonÿ   s_   é € ð	OÙ ›—?ˆDØ×!Ñ!Ô#Ø—9‘9“;Ðñ #øô ô 	OÜÐ!6°t°f¸B¸s¸eÐDÓEÈ3ÐNûð	Oüs1   ‚A„
5 Ž3�#5 ²A³5 µAÁ AÁAÁAc               ó   € V ^8„  d   QhRR/# r^   rb   )rc   s   "r-   rd   rs     s   € ÷ Vñ V˜dñ Vr/   c                	óŽ   € \        V P                  4      ;'       d*    \        P                  ! 4       V P                  ^<,
          8  # )é<   )ra   rÄ   ÚtimerÅ   r�   s   &r-   Ú_token_freshÚQQAdapter._token_fresh  s2   € Ü�D×&Ñ&Ó'×UÐU¬D¯IªI«K¸$×:PÑ:PÐSUÕ:UÑ,UÐUr/   c               ó   € V ^8„  d   QhRR/# rr   rb   )rc   s   "r-   rd   rs     s   € ÷ &ñ & Sñ &r/   c              ƒ  óÊ  a "  € S P                  4       '       d   S P                  # S P                  ;_uu_4       GRj  x€L
  S P                  4       '       d   S P                  uuRRR4      GRj  x€L
  # S P                  RV 3R l4      G Rj  x€L
 pVP	                  R4      pV'       g   \        RV 24      h\        VP	                  RR4      4      pVS n        \        P                  ! 4       V,           S n        \        P                  RS P                  V4       S P                  uuRRR4      GRj  x€L
  #  Lÿ LÎ L± L  + GRj  x€L 
 '       g   i     R# ; i5i)	zFReturn a valid access token, refreshing if needed (with singleflight).Nzaccess tokenc                 ó€   <€ S P                   P                  \        R S P                  RS P                  /\
        R7      # )ÚappIdÚclientSecret)r  Útimeout)rº   Úpostr:   ru   r±   r<   r�   s   €r-   Ú<lambda>Ú)QQAdapter._ensure_token.<locals>.<lambda>  s9   ø€ À$×BSÑBS×BXÑBXÜ ¨$¯,©,¸È×H[ÑH[Ð \Ü+ð CYô C-r/   Úaccess_tokenz,QQ Bot token response missing access_token: Ú
expires_ini   z+[%s] Access token refreshed, expires in %ds)r  rÄ   rÈ   r	  r®   r‚   r%   r  rÅ   rÝ   rå   ry   )r+   ÚdataÚtokenr  s   f   r-   Ú_ensure_tokenÚQQAdapter._ensure_token  s  øé € à×Ñ×ÒØ×%Ñ%Ð%Ø×#×#×#Ó#Ø× Ñ ×"Ò"Ø×)Ñ)÷ $×#Ò#ð ×)Ñ)¨.ô ;-ó .÷ .ˆDð —H‘H˜^Ó,ˆEßÜ"Ð%QÐRVÐQWÐ#XÓYÐYÜ˜TŸX™X l°DÓ9Ó:ˆJØ!&ˆDÔÜ%)§Y¢Y£[°:Õ%=ˆDÔ"Ü�K‰KÐEÀtÇ}Á}ÐV`ÔaØ×%Ñ%÷ $×#Ö#ñ.÷ $×#×#Ó#üs‚   ƒ;E#¾D>¿E#Á"EÁ$E#Á1E Á2E#Á7EÂEÂEÂ.A=EÄ+E#Ä8EÄ9E#Å E#ÅEÅE#ÅE 	ÅEÅ
E 	ÅE 	Å	E#c               ó   € V ^8„  d   QhRR/# rr   rb   )rc   s   "r-   rd   rs     s   € ÷ 	ñ 	¨ñ 	r/   c              ƒ  	óÖ   a a"  € S P                  4       G R j  x€L
 oS P                  RV V3R l4      G R j  x€L
 pVP                  R4      pV'       g   \        RV 24      hV#  LL L/5i)Nzgateway URLc                 ó~   <€ S P                   P                  \         \         2R RS 2R\	        4       /\
        R7      # )ÚAuthorizationúQQBot ú
User-Agent)Úheadersr  )rº   r®   r9   r;   rP   r<   ©r+   r  s   €€r-   r  Ú,QQAdapter._get_gateway_url.<locals>.<lambda>   sD   ø€ ¸T×=NÑ=N×=RÑ=RÜˆjÔ)Ð*Ð+Ø$¨¨u¨gÐ&6¸ÔFVÓFXÐYÜ'ð >Sô >)r/   Úurlz%QQ Bot gateway response missing url: )r  r	  r®   r‚   )r+   r  r)  r  s   f  @r-   Ú_get_gateway_urlÚQQAdapter._get_gateway_url  sg   ùé € Ø×(Ñ(Ó*×*ˆØ×%Ñ% mõ 6)ó *÷ *ˆð �h‰h�u‹oˆßÜÐ!FÀtÀfÐMÓNÐNØˆ
ñ +ñ*ùs%   „A)˜A%™A)·A'¸A)ÁA)Á'A)rØ   c               ó    € V ^8„  d   QhRRRR/# )r_   rØ   ra   r`   r|   rb   )rc   s   "r-   rd   rs   +  s   € ÷ )ñ )°ð )À$ñ )r/   c             ƒ  óþ   "  € V P                  4       G Rj  x€L
  V P                  4       G Rj  x€L
 pV'       d"   \        P                  RV P                  V4       V P                  V4      G Rj  x€L
  R#  L` LJ L
5i)uG   Token â†’ gateway URL â†’ WebSocket (shared by connect and _reconnect).Nz[%s] Gateway URL: %s)r  r*  rÝ   rå   ry   Ú_open_ws)r+   rØ   Úgateway_urls   &$ r-   rà   ÚQQAdapter._open_gateway_ws+  s_   é € à× Ñ Ó"×"Ð"Ø ×1Ñ1Ó3×3ˆßÜ�K‰KÐ.°·±¸{ÔKØ�m‰m˜KÓ(×(Ò(ñ	 	#Ù3ñ 	)ùs6   ‚A=–A7—A=®A9¯A=»5A=Á0A;Á1A=Á9A=Á;A=c               ó    € V ^8„  d   QhRRRR/# )r_   r/  r'   r`   r|   rb   )rc   s   "r-   rd   rs   3  s   € ÷ 	Rñ 	R¨#ð 	R°$ñ 	Rr/   c              ƒ  	óž  "  € V P                  4       G R j  x€L
  \        P                  ! \        4       R7      V n        Rp\        R \        \        P                  V4       4       R 4      pV P                  P                  VR\        4       /\        VR7      G R j  x€L
 V n        \        P                  RV P                  V4       R #  L² L.5i)N)Ú	trust_envc              3  ó8   "  € T F  q'       g   K  Vx € K  	  R # 5irf   rb   )Ú.0Úvs   & r-   Ú	<genexpr>Ú%QQAdapter._open_ws.<locals>.<genexpr>8  s   é € ÐDÑ$>˜qÃ!ŸšÓ$>ùs   ‚	�
r%  )r&  r  Úproxyz[%s] WebSocket connected to %s)Ú	WSS_PROXYÚ	wss_proxyÚHTTPS_PROXYÚhttps_proxyÚ	ALL_PROXYÚ	all_proxy)rú   ÚaiohttpÚClientSessionr   r¹   ÚnextÚmapÚosÚgetenvÚ
ws_connectrP   r>   r–   rÝ   rå   ry   )r+   r/  Ú
proxy_varsÚws_proxys   &&  r-   r.  ÚQQAdapter._open_ws3  s¢   é € Ø�n‰nÓ×Ðä×-Ò-Ô8IÓ8KÔLˆŒØgˆ
ÜÑD¤C¬¯	©	°:Ô$>ÓDÀdÓKˆØŸ™×1Ñ1Ø ,Ô0@Ó0BÐ!CÔMdÐltð 2ó 
÷ 
ˆŒô 	�‰Ð4°d·m±mÀ[ÖQñ 	ñ

ùs"   ‚C–C	—BCÂCÂ-CÃCc               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   >  s   € ÷ \"ñ \" Dñ \"r/   c              ƒ  ó.  a aa"  € ^ oRp^ oR VVV 3R llpS P                   '       d5    \        P                  ! 4       pS P                  4       G Rj  x€L
  ^ ;ooKF  R#  L  \        P
                   d     R# \         EdÏ   pS P                   '       g    Rp?R# TP                  p\        P                  RS P                  YCP                  4       \        P                  ! 4       T,
          pT\        8  dy   T^ 8”  dr   S^,          o\        P                  RS P                  TS4       S\        8¼  d;   \        P                  RS P                  4       S P!                  RR	R
R7        Rp?R# M^ oS P#                  4        S P%                  R4       S P&                  P)                  T4      pT'       dB   \        P                  RS P                  T4       S P!                  RT 2RT 2RR7        Rp?R# TR8X  d�   \        P                  RS P                  \*        4       S\,        8¼  d   S P/                  4         Rp?R# \        P0                  ! \*        4      G Rj  x€L 
  T! 4       G Rj  x€L 
   Rp?EKi  TR8X  d/   \        P                  RS P                  4       RS n        RS n        TS P6                  9   d0   \        P                  RS P                  T4       RS n        RS n        T! 4       G Rj  x€L 
  S\,        8¼  d7   \        P                  RS P                  4       S P/                  4         Rp?R#  Rp?EK6  Rp?i\<         d¸   pS P                   '       g    Rp?R# \        P                  RS P                  T4       S P#                  4        S P%                  R4       S\,        8¼  d7   \        P                  RS P                  4       S P/                  4         Rp?R# T! 4       G Rj  x€L 
   Rp?EKö  Rp?ii ; i5i)uÃ   Read WebSocket events and reconnect on errors. Close codes: 4004 â†’ refresh
token; 4006/4007/49xx â†’ clear session and re-identify; 4008 â†’ rate limited,
back off; _FATAL_CLOSE_CODES â†’ stop.r«   c               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   Ú,QQAdapter._listen_loop.<locals>.__annotate__F  s   € ÷ 	!ñ 	! ñ 	!r/   c               “  óp   <"  € SP                  S 4      G R j  x€L
 '       d   ^ ;o oR # S ^,          o R #  L5irf   )Ú
_reconnect)Úbackoff_idxÚquick_disconnect_countr+   s   €€€r-   Ú	reconnectÚ)QQAdapter._listen_loop.<locals>.reconnectF  s2   øé € à—_‘_ [Ó1×1Ö1Ø78Ð8�Ò4à˜qÕ ’ñ 2ùs   ƒ6˜4™	6£6Nz([%s] WebSocket closed: code=%s reason=%sz([%s] Quick disconnect (%.1fs), count: %dzf[%s] Too many quick disconnects. Check: 1) AppID/Secret correct 2) Bot permissions on QQ Open PlatformÚqq_quick_disconnectu4   Too many quick disconnects â€” check bot permissionsTrÖ   zConnection closedz'[%s] Bot is %s. Check QQ Open Platform.Úqq_zBot is Fi¨  z%[%s] Rate limited (4008), waiting %dsi¤  z5[%s] Invalid token (4004), will refresh and reconnectz9[%s] Session error (%d), clearing session for re-identifyz2[%s] Max reconnect attempts reached (QQCloseError)z[%s] WebSocket error: %szConnection interruptedz#[%s] Max reconnect attempts reached)r•   r  Ú	monotonicÚ_read_eventsrÆ   ÚCancelledErrorr!   r&   rÝ   rÞ   ry   r(   rB   rå   rC   rè   rÜ   r‘   r…   Ú_FATAL_CLOSE_CODESr®   rA   r@   rô   ÚsleeprÄ   rÅ   Ú_SESSION_INVALID_CLOSE_CODESr¾   r¿   rç   )	r+   Úconnect_timerR  rï   r&   ÚdurationÚdescrP  rQ  s	   f      @@r-   râ   ÚQQAdapter._listen_loop>  s<  úé € ð ˆØˆØ!"Ð÷	!ò 	!ð �m�mˆmðL"Ü#Ÿ~š~Ó/�Ø×'Ñ'Ó)×)Ð)Ø78Ð8�Ò4ñ	 ñ *øä×)Ñ)ô ÚÜõ 9Ø—}—}�}ÝØ—x‘x�Ü—‘ÐIÈ4Ï=É=ÐZ^×`jÑ`jÔkô  Ÿ>š>Ó+¨lÕ:�ØÔ8Ô8¸\ÈAÔ=MØ*¨aÕ/Ð*Ü—K‘KØBÀDÇMÁMÐS[Ð]sôð .Ô1KÔKÜŸ™ðdà ŸM™Mô+ð ×-Ñ-Ø1Ð3iÐuyð .ô õ ð Lð ./Ð*à×1Ñ1Ô3Ø×"Ñ"Ð#6Ô7à×.Ñ.×2Ñ2°4Ó8�ßÜ—L‘LÐ!JÈDÏMÉMÐ[_Ô`Ø×)Ñ)¨C°¨v¨,¸'À$ÀÐ8HÐTYÐ)ÔZÝà˜4”<Ü—K‘KÐ GÈÏÉÔXhÔiØ"Ô&<Ô<Ø×/Ñ/Ô1ÝÜ!Ÿ-š-Ô(8Ó9×9Ñ9Ù#›+×%Ñ%Þà˜4”<Ü—K‘KÐ WÐY]×YfÑYfÔgØ)-�DÔ&Ø-0�DÔ*à˜4×<Ñ<Ô<Ü—K‘KÐ [Ð]a×]jÑ]jÐlpÔqØ'+�DÔ$Ø%)�D”Ná“k×!Ñ!ØÔ"8Ô8Ü—L‘LÐ!UÐW[×WdÑWdÔeØ×+Ñ+Ô-Ýö 9ûô
 ô "Ø—}—}�}ÝÜ—‘Ð9¸4¿=¹=È#ÔNØ×1Ñ1Ô3Ø×"Ñ"Ð#;Ô<àÔ"8Ô8Ü—L‘LÐ!FÈÏÉÔVØ×+Ñ+Ô-ÝÙ“k×!×!Ð!ûð"üsú   …#Pª(A! ÁAÁA! ÁPÁA! Á!PÁ6PÁ9	PÂPÂMÂPÂCMÅ+PÅ1AMÆ8;MÇ3PÇ9AMÉ PÉMÉ#I&É$MÉ3I6É4MÉ9PÊ A?MË?LÌ A MÍ PÍPÍPÍPÍ-PÍ3A=PÏ0PÏ6
PÐ PÐPÐPÐPÐPc               ó    € V ^8„  d   QhRRRR/# )r_   rP  r%   r`   ra   rb   )rc   s   "r-   rd   rs   œ  s   € ÷ ñ ¨Cð °Dñ r/   c              ƒ  	ó  "  € \         \        V\        \         4      ^,
          4      ,          p\        P	                  RV P
                  W!^,           4       \        P                  ! V4      G Rj  x€L
  RV n         V P                  4       G Rj  x€L
  V P                  4        \        P	                  RV P
                  4       R#  LV L8  \         d-   p\        P                  RT P
                  T4        Rp?R# Rp?ii ; i5i)é   z([%s] Reconnecting in %ds (attempt %d)...Nr¨   z[%s] ReconnectedTz[%s] Reconnect failed: %sF)r?   ÚminÚlenrÝ   rå   ry   rÆ   rZ  r½   rà   rä   rç   rÞ   )r+   rP  Údelayrï   s   &&  r-   rO  ÚQQAdapter._reconnectœ  sÂ   é € Ü!¤# k´3Ô7HÓ3IÈAÕ3MÓ"NÕOˆÜ�‰Ð>ÀÇÁÈuÐdeÕVeÔfÜ�mŠm˜EÓ"×"Ð"à#'ˆÔ ð	Ø×'Ñ'Ó)×)Ð)Ø× Ñ Ô"Ü�K‰KÐ*¨D¯M©MÔ:Ùñ 	#ñ *øô ô 	Ü�N‰NÐ6¸¿¹ÀsÔKÝûð	üsN   ‚A-DÁ/CÁ0DÁ<C
 ÂCÂ4C
 ÃDÃC
 Ã
DÃ!C<Ã6DÃ<DÄDc               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   «  s   € ÷ 7ñ 7 Dñ 7r/   c              ƒ  	ód  "  € V P                   '       g   \        R 4      hV P                   P                  '       d   \        R4      hV P                  '       EdR   V P                   '       Ed=   V P                   P                  '       Eg   V P                   P	                  4       G Rj  x€L
 pVP
                  \        P                  P                  8X  d9   V P                  VP                  4      pV'       d   V P                  V4       KÄ  KÆ  VP
                  \        P                  P                  8X  d!   \        VP                  VP                  4      hVP
                  \        P                  P                  \        P                  P                   09   g   EKU  \        R4      hR# R# R#  EL5i)zWebSocket not connectedzWebSocket closedN)r–   r‚   r—   r•   ÚreceiveÚtyper@  Ú	WSMsgTypeÚTEXTÚ_parse_jsonr  Ú_dispatch_payloadÚCLOSEr!   r­   ÚCLOSEDÚERROR)r+   ÚmsgÚpayloads   &  r-   rW  ÚQQAdapter._read_events«  s  é € Ø�x�xˆxÜÐ8Ó9Ð9Ø�8‰8�?�?ˆ?ô Ð1Ó2Ð2à�m�m‰m §§¡°·±··±ØŸ™×(Ñ(Ó*×*ˆCØ�x‰xœ7×,Ñ,×1Ñ1Ô1Ø×*Ñ*¨3¯8©8Ó4�ßØ×*Ñ*¨7Ö3ñ à—‘œW×.Ñ.×4Ñ4Ô4Ü" 3§8¡8¨S¯Y©YÓ7Ð7Ø—‘œg×/Ñ/×6Ñ6¼×8IÑ8I×8OÑ8OÐP×PÜ"Ð#5Ó6Ð6ñ 2A¡‰mÚ*ùs6   ‚9F0¼F0ÁF0Á-F0Â
F0Â'F-Â(AF0Ã8BF0ÆF0c               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   ¾  s   € ÷ 
Rñ 
R tñ 
Rr/   c              ƒ  óZ  "  € \         P                  ! \        P                  4      ;_uu_ 4        V P                  '       d�   \        P
                  ! V P                  4      G Rj  x€L
  V P                  '       d   V P                  P                  '       d   Kj   V P                  P                  R^RV P                  /4      G Rj  x€L
  Kž   RRR4       R#  Ls L  \         d-   p\        P                  RT P                  T4        Rp?Kß  Rp?ii ; i  + '       g   i     R# ; i5i)zFSend op 1 heartbeats with the latest seq at 80% of the Hello interval.NÚopÚdz[%s] Heartbeat failed: %s)Ú
contextlibÚsuppressrÆ   rX  r•   rZ  r½   r–   r—   Ú	send_jsonr¿   rç   rÝ   Údebugry   )r+   rï   s   & r-   rã   ÚQQAdapter._heartbeat_loop¾  sË   é € ä× Ò ¤×!7Ñ!7×8Õ8Ø—-—-�-Ü—m’m D×$<Ñ$<Ó=×=Ð=Ø—x—x�x 4§8¡8§?§? ?ÙðRØŸ(™(×,Ñ,¨d°A°s¸D¿N¹NÐ-KÓL×LÒLð  ÷ 9Ñ8á=ñ MøÜ ô RÜ—L‘LÐ!<¸d¿m¹mÈS×QÒQûðRú÷ 9×8Ð8üs|   ‚-D+¯DÁ#DÁ%CÁ&DÁ<DÂDÂ,CÃCÃCÃDÃ
D+ÃDÃCÃDÃ(!DÄ	DÄDÄDÄD(	Ä"	D+c               ó(   € V ^8„  d   QhRRRRRRRR/# )r_   rÎ   r'   rs  r  Úsent_msgr`   ra   rb   )rc   s   "r-   rd   rs   Ê  s*   € ÷ ñ ¨ð °nð ÐPSð Ðcgñ r/   c              ‡  óÆ  "  €  V P                   '       dl   V P                   P                  '       gP   V P                   P                  V4      G Rj  x€L
  \        P                  ! RV,           V P
                  .VO5!   R# \        P                  RV P
                  V4        R#  LT  \         d-   p\        P                  RT P
                  Y4        Rp?R# Rp?ii ; i5i)zBSend an Identify/Resume payload; returns False if the send raised.Nz[%s] z,[%s] Cannot send %s: WebSocket not connectedz[%s] Failed to send %s: %sFT)	r–   r—   r{  rÝ   rå   ry   rÞ   rç   rè   )r+   rÎ   rs  r  Úlog_argsrï   s   &&&&* r-   Ú_send_ws_authÚQQAdapter._send_ws_authÊ  s£   é € ð	Ø�x�xˆx §¡§§ Ø—h‘h×(Ñ(¨Ó1×1Ð1Ü—’˜G hÕ.°·±ÐIÀÔIñ ô	 —‘ÐMÈtÏ}É}Ð^bÕcñ ñ 2øô ô 	Ü�L‰LÐ5°t·}±}ÀdÔPÝûð	üsQ   ‚C!„-B' ²B' ÁB%Á.B' Á?C!Â!B' Â"C!Â%B' Â'CÂ2!CÃC!ÃCÃC!c               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   ×  s   € ÷ 	Gñ 	G dñ 	Gr/   c              ƒ  ó®   "  € V P                  4       G Rj  x€L
 pR^RRRV 2RRR^ ^.RR	R
RRRR///pV P                  RVR4      G Rj  x€L
  R#  L: L5i)z–Send op 2 Identify (reply to Hello); server answers with READY. Intents:
C2C_GROUP_AT_MESSAGES | PUBLIC_GUILD_MESSAGES | DIRECT_MESSAGE | INTERACTION.Nrw  rx  r  r$  ÚintentsÚshardÚ
propertiesz$osÚmacOSz$browserzhermes-agentz$deviceÚIdentifyzIdentify senti  F)r  r‚  ©r+   r  rs  s   &  r-   Ú_send_identifyÚQQAdapter._send_identify×  s€   é € ð ×(Ñ(Ó*×*ˆØ˜˜CØ�v˜e˜WÐ%ØÐDØ�a˜�VØ˜5 '¨:°~ÀyÐR`Ðað	"cð dˆð
 × Ñ  ¨W°oÓF×FÒFñ +ñ 	Gùs!   ‚A–A—3AÁ
AÁAÁAc               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   â  s   € ÷ "ñ " Dñ "r/   c           	   ƒ  ó  "  € V P                  4       G Rj  x€L
 pR^RRRV 2RV P                  RV P                  //pV P                  RVR	V P                  V P                  4      G Rj  x€L
 '       g   RV n        RV n        R# R#  Lp L5i)
uU   Send op 6 Resume after a reconnect; on failure clear session â†’ Identify next Hello.Nrw  rx  r  r$  Ú
session_idÚseqÚResumez#Resume sent (session_id=%s, seq=%s))r  r¾   r¿   r‚  r‹  s   &  r-   Ú_send_resumeÚQQAdapter._send_resumeâ  s—   é € à×(Ñ(Ó*×*ˆØ˜˜C '¨V°E°7Ð+;¸\È4×K[ÑK[Ð]bÐdh×drÑdrÐ!sÐtˆØ×'Ñ'Ø�gÐDÀd×FVÑFVÐX\×XfÑXfó
÷ 
ö 
ð  $ˆDÔØ!ˆDŽNñ	
ñ +ñ
ùs(   ‚B–B—ABÁ*B	Á+	BÁ5BÂ	Bc                óp   €  \         P                  ! 4       P                  V 4      #   \         d     R# i ; i)zsSchedule a coroutine; returns None (no error) when no loop is running
(tests call _dispatch_payload synchronously).N)rÆ   Úget_running_looprá   r‚   )Úcoros   &r-   Ú_create_taskÚQQAdapter._create_taskì  s3   € ð	Ü×+Ò+Ó-×9Ñ9¸$Ó?Ð?øÜô 	Úð	ús   ‚#& ¦5´5c               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   õ  s   € ÷ 0ñ 0 ñ 0r/   c                ó¼   € V P                   '       dJ   V P                   P                  '       g,   V P                  V P                   P                  4       4       R# R# R# )zNClose the WS so _read_events raises and _listen_loop reconnects (with Resume).N)r–   r—   r˜  rù   r�   s   &r-   Ú_close_ws_soonÚQQAdapter._close_ws_soonõ  s7   € à�8�8ˆ8˜DŸH™HŸOŸO˜OØ×Ñ˜dŸh™hŸn™nÓ.Ö/ñ ,‰8r/   c               ó    € V ^8„  d   QhRRRR/# )r_   rs  r  r`   r|   rb   )rc   s   "r-   rd   rs   ú  s   € ÷ )Cñ )C¨ð )C¸Dñ )Cr/   c                óš  € VP                  R4      VP                  R4      VP                  R4      VP                  R4      3w  r#rE\        V\        4      '       d%   V P                  e   W@P                  8”  d   W@n        V^
8X  dÆ   \        V\        4      '       d   TM/ P                  RR4      pVR,          R	,          V n        \        P                  R
V P                  W`P
                  4       V P                  ;'       d    V P                  RJpT P                  V'       d   V P                  4       MV P                  4       4       R# V^ 8X  Ed   V'       Ed   VR8X  d\   \        V\        4      '       dD   VP                  R4      V n	        \        P                  RV P                  V P                  4       R# R# VR8X  d#   \        P                  RV P                  4       R# W0P                  9   d(   \        P                   ! V P#                  W54      4       R# VR8X  d#   V P                  V P%                  V4      4       R# \        P                  RV P                  V4       R# V^8X  d   R# V^8X  d3   \        P                  RV P                  4       V P'                  4        R# V^	8X  dw   Ve3   \)        V4      '       d"   \        P                  RV P                  4       M.\        P                  RV P                  4       RV n	        RV n        V P'                  4        R# \        P                  RV P                  V4       R# )zPRoute inbound WebSocket payloads (dispatch synchronously, spawn async handlers).rw  ÚtÚsrx  NÚheartbeat_intervali0u  g     @�@gš™™™™™é?zB[%s] Hello received, heartbeat_interval=%dms (sending every %.1fs)ÚREADYr�  z[%s] Ready, session_id=%sÚRESUMEDz[%s] Session resumedÚINTERACTION_CREATEz[%s] Unhandled dispatch: %sz&[%s] Server requested reconnect (op 7)z&[%s] Invalid session (op 9, resumable)z<[%s] Invalid session (op 9, not resumable), clearing sessionz[%s] Unknown op: %s)r®   Ú
isinstancer%   r¿   Údictr½   rÝ   r|  ry   r¾   r˜  r“  rŒ  rå   Ú_INBOUND_HANDLERSrÆ   rá   Ú_on_messageÚ_on_interactionrœ  ra   )r+   rs  rw  r   r¡  rx  Úinterval_msÚresumes   &&      r-   rn  ÚQQAdapter._dispatch_payloadú  s^  € à—k‘k $Ó'¨¯©°SÓ)9¸7¿;¹;ÀsÓ;KÈWÏ[É[ÐY\ÓM]Ð]‰ˆˆqÜ�aœ×Ò 4§>¡>Ò#9¸QÇÁÔ=OØŒNà�Œ8Ü *¨1¬d× 3Ò 3™1¸×@Ñ@ÐAUÐW\Ó]ˆKØ'2°VÕ';¸cÕ'AˆDÔ$Ü�L‰LØTØ—‘˜{×,DÑ,DôFð ×%Ñ%×DÐD¨$¯.©.ÀÐ*DˆFØ×Ñ·V˜d×/Ñ/Ô1À×ATÑATÓAVÖWØ�1�WŸ˜Ø�GŒ|Ü˜a¤×&Ò&Ø'(§u¡u¨\Ó':�DÔ$Ü—K‘KÐ ;¸T¿]¹]ÈD×L\ÑL\Ö]ñ 'ð �i”Ü—‘Ð2°D·M±MÖBØ×,Ñ,Ô,Ü×#Ò# D×$4Ñ$4°QÓ$:Ö;ØÐ*Ô*Ø×!Ñ! $×"6Ñ"6°qÓ"9Ö:ä—‘Ð:¸D¿M¹MÈ1ÖMØ�2ŒXÙØ�1ŒWÜ�K‰KÐ@À$Ç-Á-ÔPØ×ÑÖ!Ø�1ŒWØŠ}¤ a§¢Ü—‘ÐDÀdÇmÁmÕTä—‘ÐZÐ\`×\iÑ\iÔjØ#'�Ô Ø!%�”Ø×ÑÖ!ä�L‰LÐ.°·±¸rÖBr/   c               ó    € V ^8„  d   QhRRRR/# )r_   Úrawr   r`   úOptional[dict[str, Any]]rb   )rc   s   "r-   rd   rs   (  s   € ÷ >ñ >˜ð >Ð!9ñ >r/   c                	ó´   €  \         P                  ! V 4      p\        T\        4      '       d   T# R#   \         d    \        P	                  R T 4        R# i ; i)z [QQBot] Failed to parse JSON: %rN)r  Úloadsrç   rÝ   rÞ   r¦  r§  )r¯  rs  s   & r-   rm  ÚQQAdapter._parse_json'  sP   € ð	Ü—j’j “oˆGô % W¬d×3Ò3ˆwÐ=¸Ð=øô ô 	Ü�N‰NÐ=¸sÔCÚð	ús   ‚2 ²!AÁAc               ó    € V ^8„  d   QhRRRR/# )r_   Úmsg_idr'   r`   r%   rb   )rc   s   "r-   rd   rs   1  s   € ÷ *ñ *˜cð * cñ *r/   c                óÊ   € \        \        P                  ! 4       4      R,          p\        \        P                  ! 4       P                  R,          ^4      pW,          R,          # )z5Generate a message sequence number in 0..65535 range.i áõ:Né   Ni   )r%   r  ÚuuidÚuuid4Úhex)rµ  Ú	time_partÚrands   &  r-   Ú_next_msg_seqÚQQAdapter._next_msg_seq0  sD   € ô œŸ	š	›Ó$ yÕ0ˆ	Ü”4—:’:“<×#Ñ# BÕ'¨Ó,ˆØÕ  EÕ)Ð)r/   c               ó    € V ^8„  d   QhRRRR/# )r_   Úeventr   r`   r|   rb   )rc   s   "r-   rd   rs   9  s   € ÷ ,ñ ,¨,ð ,¸4ñ ,r/   c              ƒ  óø   <"  € VP                   '       dJ   VP                  P                  '       d.   VP                   V P                  VP                  P                  &   \        SV `  V4      G Rj  x€L
  R#  L5i)z:Cache the last message ID per chat, then delegate to base.N)Ú
message_idÚsourceÚchat_idrÂ   r)   Úhandle_message)r+   rÀ  r,   s   &&€r-   rÅ  ÚQQAdapter.handle_message9  sT   øé € à××Ð §¡× 4× 4Ð 4Ø6;×6FÑ6FˆD×Ñ˜eŸl™l×2Ñ2Ñ3Ü‰gÑ$ UÓ+×+Ô+ùs   ƒ.A:²?A:Á1A8Á2A:c               ó$   € V ^8„  d   QhRRRRRR/# )r_   Ú
event_typer'   rx  r   r`   r|   rb   )rc   s   "r-   rd   rs   ?  s&   € ÷ cñ c¨Cð c°Cð c¸Dñ cr/   c              ƒ  	ó‚  "  € \        V\        4      '       g   R # \        VP                  RR4      4      pV'       d"   V P                  P                  V4      '       d$   \        P                  RV P                  V4       R # V P                  P                  V4      pV'       d—   \        VP                  R4      \        4      '       d   VP                  R4      M/ p\        W4      ! W#\        VP                  RR4      4      P                  4       V\        VP                  RR4      4      4      G R j  x€L
  R # R #  L5i)NÚidr#   z([%s] Duplicate or missing message id: %sÚauthorÚcontentÚ	timestamp)r¦  r§  r'   r®   rÁ   Úis_duplicaterÝ   r|  ry   r¨  rw   r°   )r+   rÈ  rx  rµ  ÚhandlerrË  s   &&&   r-   r©  ÚQQAdapter._on_message?  sî   é € Ü˜!œT×"Ò"ÙÜ�Q—U‘U˜4 “_Ó%ˆß˜Ÿ™×1Ñ1°&×9Ò9Ü�L‰LÐCÀTÇ]Á]ÐTZÔ[ÙØ×(Ñ(×,Ñ,¨ZÓ8ˆßÜ(2°1·5±5¸³?ÄD×(IÒ(I�Q—U‘U˜8”_ÈrˆFÜ˜$Ô(Øœ3˜qŸu™u Y°Ó3Ó4×:Ñ:Ó<¸fÄcÈ!Ï%É%ÐP[Ð]_ÓJ`ÓFaóc÷ cò cñ ñcùs    ‚AD?ÁAD?Â%BD?Ä4D=Ä5	D?c               ó    € V ^8„  d   QhRRRR/# )r_   Úcallbackz7Optional[Callable[[InteractionEvent], Awaitable[None]]]r`   r|   rb   )rc   s   "r-   rd   rs   N  s   € ÷ .ñ .Ð1hð .Ðmqñ .r/   c                ó   € Wn         R# )zFRegister (or clear) the callback invoked per ACKed INTERACTION_CREATE.N)rÊ   )r+   rÒ  s   &&r-   Úset_interaction_callbackÚ"QQAdapter.set_interaction_callbackN  s   € à%-Ö"r/   c               ó    € V ^8„  d   QhRRRR/# )r_   rx  r   r`   r|   rb   )rc   s   "r-   rd   rs   R  s   € ÷ dñ d sð d¨tñ dr/   c              ƒ  ó¢  "  € \        V\        4      '       g   R#  \        V4      pTP                  '       g#   \        P                  RT P                  4       R#  T P                  TP                  4      G Rj  x€L
  \        P                  RT P                  TP                  TP                  TP                  4       T P                  pTf.   \        P                  RT P                  TP                  4       R#  T! T4      G Rj  x€L
  R#   \         d-   p\        P                  RT P                  T4        Rp?R# Rp?ii ; i LÏ  \         d8   p\        P                  RT P                  TP                  T4        Rp?EL
Rp?ii ; i L‡  \         d/   p\        P                  RT P                  TRR	7        Rp?R# Rp?ii ; i5i)
zˆParse INTERACTION_CREATE, ACK it promptly (else the client shows an error
icon on the button), then dispatch to the registered callback.Nz+[%s] Failed to parse INTERACTION_CREATE: %sz0[%s] INTERACTION_CREATE missing id, skipping ACKz%[%s] Failed to ACK interaction %s: %sz5[%s] Interaction: scene=%s button_data=%r operator=%szA[%s] No interaction callback registered; dropping button click %rz$[%s] Interaction callback raised: %sTrÚ   )r¦  r§  rZ   rç   rÝ   rÞ   ry   rÊ  Ú_acknowledge_interactionrå   ÚsceneÚbutton_dataÚoperator_openidrÊ   r|  rè   )r+   rx  rÀ  rï   rÒ  s   &&   r-   rª  ÚQQAdapter._on_interactionR  sx  é € ô ˜!œT×"Ò"Ùð	Ü+¨AÓ.ˆEð �x�xˆxÜ�N‰NÐMÈtÏ}É}Ô]Ùð	bØ×/Ñ/°·±Ó9×9Ð9ô 	�‰ØCØ�M‰M˜5Ÿ;™;¨×(9Ñ(9¸5×;PÑ;Pô	Rð ×-Ñ-ˆØÒÜ�L‰LØSÐUY×UbÑUbÐdi×duÑduôñ ð	dÙ˜5“/×!Ò!øô- ô 	Ü�N‰NÐHÈ$Ï-É-ÐY\Ô]Ýûð	úñ :øÜô 	bÜ�N‰NÐBÀDÇMÁMÐSX×S[ÑS[Ð]`×aÒaûð	búñ "øÜô 	dÜ�L‰LÐ?ÀÇÁÐPSÐ^bˆL×cÒcûð	düs«   ‚GœD §G¹"GÁE Á:E
Á;E Á?A>GÃ>F Ä	FÄ
F ÄGÄEÄ!EÄ<GÅEÅGÅ
E ÅFÅ,F	ÆGÆ	FÆGÆF ÆGÆ#GÇGÇGÇGc               ó$   € V ^8„  d   QhRRRRRR/# )r_   Úinteraction_idr'   r&   r%   r`   r|   rb   )rc   s   "r-   rd   rs   s  s'   € ÷ bñ b¸Sð bÈð bÐTXñ br/   c              ƒ  ó0  "  € V P                  4       P                  \         RV 2V P                  4       G Rj  x€L
 RV/\        R7      G Rj  x€L
 pVP
                  R8¼  d-   \        RVP
                   RVP                  R,           24      hR#  LX LE5i)	zKACK a button interaction via ``PUT /interactions/{id}`` (code 0 = success).z/interactions/Nr&   ©r&  r  r  é�  zInteraction ACK failed [ú]: ºNéÈ   N)Ú_require_http_clientÚputr9   Ú_auth_headersr<   Ústatus_coder‚   Útext)r+   rÞ  r&   r  s   &&& r-   rØ  Ú"QQAdapter._acknowledge_interactions  s›   é € à×.Ñ.Ó0×4Ñ4Üˆj˜ ~Ð&6Ð7Ø×,Ñ,Ó.×.°f¸d°^ÔM`ð 5ó b÷ bˆð ×Ñ˜sÔ"ÜÐ!9¸$×:JÑ:JÐ9KÈ3ÈtÏyÉyÐY]ÍÐN_Ð`ÓaÐañ #ñ /ñbùs"   ‚7B¹B
ºBÁBÁABÂBz
allow-onceÚoncezallow-alwaysÚalwaysÚdenyc               ó    € V ^8„  d   QhRRRR/# )r_   Úsession_keyr'   r`   zOptional[dict[str, str]]rb   )rc   s   "r-   rd   rs   €  s   € ÷ ñ °ð Ð8Pñ r/   c                ó  € \        T ;'       g    R4      P                  R4      p\        V4      ^8  g   V^ ,          R8w  g   V^,          '       g   R# RV^,          RV^,          RV^,          /p\        V4      ^8”  d   V^,          VR&   V# )	uM  Parse ``agent:<namespace>:<platform>:<chat_type>:<chat_id>[:<user_id>]``.

The namespace slot carries the multiplex profile ("main" for the
default profile â€” see ``gateway.session._session_key_namespace``);
it takes no part in any authorization decision, so any non-empty
value is accepted and every later slot keeps its position.
r#   Ú:ÚagentNÚplatformÚ	chat_typerÄ  Úuser_id)r'   Úsplitrd  )rï  ÚpartsÚparseds   &  r-   Ú_parse_gateway_session_keyÚ$QQAdapter._parse_gateway_session_key  s   € ô �K×%Ð% 2Ó&×,Ñ,¨SÓ1ˆÜˆu‹:˜Œ>˜U 1�X¨Ô0¸¸a¿¼ÙØ˜e A�h¨°U¸1µX¸yÈ%ÐPQÍ(ÐSˆÜˆu‹:˜Œ>Ø % a¥ˆF�9ÑØˆr/   c               ó$   € V ^8„  d   QhRRRRRR/# )r_   rÀ  rV   rï  r'   r`   ra   rb   )rc   s   "r-   rd   rs   �  s$   € ÷ ñ Ð<Lð Ð[^ð Ðcgñ r/   c                ó†  € V P                  V4      p\        VP                  ;'       g    R4      P                  4       pV'       d   VP	                  R4      R8w  g	   V'       g   R# VP	                  RR4      pVP	                  RR4      pVR9   d   \        V4      ;'       d    WF8H  # VR	9   d’   \        VP                  ;'       g    VP                  ;'       g    R4      P                  4       pV'       d   Wv8w  d   R# \        VP	                  RR4      4      P                  4       p\        V4      ;'       d    WH8H  # R# )
zBAuthorize approval/update interactions against session + operator.r#   ró  ÚqqbotFrô  rÄ  rõ  >   ÚdmÚc2c>   ÚgroupÚguild)rù  r'   rÛ  r°   r®   ra   Úgroup_openidÚguild_id)	r+   rÀ  rï  rø  Úoperatorrô  rÄ  Ú
event_chatÚsession_users	   &&&      r-   Ú&_is_authorized_interaction_for_sessionÚ0QQAdapter._is_authorized_interaction_for_session�  s   € à×0Ñ0°Ó=ˆÜ�u×,Ñ,×2Ð2°Ó3×9Ñ9Ó;ˆß˜Ÿ™ JÓ/°7Ô:Ç(Ùà—J‘J˜{¨BÓ/ˆ	Ø—*‘*˜Y¨Ó+ˆà˜Ô%Ü˜“=×8Ð8 XÑ%8Ð8ØÐ*Ô*Ü˜U×/Ñ/×GÐG°5·>±>×GÐGÀRÓH×NÑNÓPˆJß Ô!6ÙÜ˜vŸz™z¨)°RÓ8Ó9×?Ñ?ÓAˆLÜ˜Ó%×BÐB¨(Ñ*BÐBÙr/   c               ó$   € V ^8„  d   QhRRRRRR/# )r_   rÀ  rV   Úchatr'   r`   rb   )rc   s   "r-   rd   rs   ¤  s(   € ÷ `ñ `Ð0@ð `Èð `ÐPSñ `r/   c                óX   € V P                  V P                  W!P                  R7      4      # )a
  Session key an update-prompt click is authorized against, built by the ONE key builder so
it carries the profile namespace (a hard-coded ``agent:main:`` prefix never matched a
multiplexed secondary bot's lane). No participant: ``c2c`` authorizes on chat == operator.)rÄ  rô  )Ú_source_session_keyÚbuild_sourcerÙ  )r+   rÀ  r
  s   &&&r-   Ú_update_prompt_session_keyÚ$QQAdapter._update_prompt_session_key¤  s)   € ð ×'Ñ'¨×(9Ñ(9À$×R]ÑR]Ð(9Ó(^Ó_Ð_r/   c               ó    € V ^8„  d   QhRRRR/# )r_   rÀ  rV   r`   r|   rb   )rc   s   "r-   rd   rs   ª  s   € ÷ )sñ )sÐ9Ið )sÈdñ )sr/   c              ƒ  ó  "  € VP                   pV'       g   R# \        V4      pVeÈ   Vw  rEV P                  P                  V4      pVf$   \        P                  RV P                  WT4       R# V P                  W4      '       g.   \        P                  RV P                  WAP                  4       R#  ^ RI	H
p V! WF4      p\        P                  RV P                  W„WaP                  4       R# \        V4      p
V
e¥   VP                  ;'       g!    VP                   ;'       g    VP"                  pV P                  WP%                  W4      4      '       g.   \        P                  RV P                  VP                  4       R# V P'                  W¡P                  4       R# \        P)                  RV P                  W!P*                  4       R#   \         d-   p	\        P                  RT P                  YI4        Rp	?	R# Rp	?	ii ; i5i)	uÑ   Default interaction callback: ``approve:<session_key>:<decision>`` â†’
tools.approval.resolve_gateway_approval; ``update_prompt:<answer>`` â†’
``~/.hermes/.update_response``; anything else is ignored at DEBUG.Nz.[%s] Unknown approval decision %r (session=%s)zF[%s] Rejected unauthorized approval click for session %s (operator=%s))Úresolve_gateway_approvalzK[%s] Button resolved %d approval(s) for session %s (choice=%s, operator=%s)z7[%s] resolve_gateway_approval failed for session %s: %sz<[%s] Rejected unauthorized update prompt click (operator=%s)z4[%s] Unrecognised button_data %r from interaction %s)rÚ  rY   Ú_APPROVAL_BUTTON_TO_CHOICEr®   rÝ   rÞ   ry   r  rÛ  Útools.approvalr  rå   rç   rè   r[   r  r  Úuser_openidr  Ú_write_update_responser|  rÊ  )r+   rÀ  rÚ  Úapprovalrï  ÚdecisionÚchoicer  Úcountrï   Úupdate_answerr
  s   &&          r-   rÉ   Ú'QQAdapter._default_interaction_dispatchª  s²  é € ð ×'Ñ'ˆßÙä-¨kÓ:ˆØÒØ$,Ñ!ˆKØ×4Ñ4×8Ñ8¸ÓBˆFØŠ~Ü—‘ÐOÐQU×Q^ÑQ^Ð`hÔvÙØ×>Ñ>¸u×RÒRÜ—‘Ø\Ø—M‘M ;×0EÑ0EôGñ ðyÝCÙ0°ÓE�Ü—‘ØaØ—M‘M 5°v×?TÑ?TôVñ
 ä7¸ÓDˆØÒ$Ø×%Ñ%×LÐL¨¯©×LÐL¸5×;LÑ;LˆDØ×>Ñ>¸u×FeÑFeÐfkÓFr×sÒsÜ—‘ØRÐTX×TaÑTaÐch×cxÑcxôñ Ø×'Ñ'¨×7LÑ7LÔMÙä�‰ÐKÈTÏ]É]Ð\g×iqÑiqÖrøô ô yÜ—‘ÐVÐX\×XeÑXeÐgr×xÐxÙûðyüs=   ‚B0H	Â3:G Ã-#H	ÄH	Ä%B*H	ÇHÇ!HÇ;H	ÈHÈH	c               ó$   € V ^8„  d   QhRRRRRR/# )r_   Úanswerr'   r  r`   r|   rb   )rc   s   "r-   rd   rs   Ö  s&   € ÷ Eñ E sð E°cð EÀ4ñ Er/   c                ó8  €  ^ RI Hp V! 4       R,          pVP                  R4      pVP                  V RR7       VP	                  V4       \
        P                  RY;'       g    R4       R	#   \         d"   p\
        P                  RT4        R	p?R	# R	p?ii ; i)
z�Atomically (tmp + rename) write the update-prompt answer to
``.update_response``, polled by the detached ``hermes update --gateway`` watcher.)Úget_hermes_homez.update_responsez.tmpzutf-8)Úencodingz"QQ update prompt answered %r by %sz	(unknown)z#Failed to write update response: %sN)	Úhermes_constantsr   Úwith_suffixÚ
write_textÚreplacerÝ   rå   rç   rè   )r  r  r   Úresponse_pathÚtmprï   s   &&    r-   r  Ú QQAdapter._write_update_responseÕ  s�   € ð	EÝ8Ù+Ó-Ð0BÕBˆMØ×+Ñ+¨FÓ3ˆCØ�N‰N˜6¨GˆNÔ4Ø�K‰K˜Ô&Ü�K‰KÐ<¸f×F]ÐF]ÐR]Ö^øÜô 	EÜ�L‰LÐ>À×DÒDûð	Eús   ‚A!A- Á$A- Á-BÁ8BÂBc               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   ã  s   € ÷ Zñ ZÐRVñ Zr/   c              ƒ  	ó
  "  € \        VP                  R R4      4      pV'       d   V P                  V4      '       g   R# VP                  R4      p\        P	                  RV P
                  Y#'       d
   VR,          MRV'       d'   \        V\        4      '       d   \        V4      M^  R2MR4       V'       d¦   \        V\        4      '       d�   \        V4       F€  w  r‰\        V	\        4      '       g   K  \        P	                  RV P
                  W‰P                  R	R4      \        V	P                  R
R4      4      R,          V	P                  RR4      4       K‚  	  V P                  WW7VRVRVRR7
      G Rj  x€L
  R#  L5i)r  r#   NÚattachmentsz1[%s] C2C message: id=%s content=%r attachments=%sºNé2   Nz itemsr|   z7[%s] attachment[%d]: content_type=%s url=%s filename=%sÚcontent_typer)  ºNéP   NÚfilenameTrÿ  rþ  )ÚverboserÄ  Úqq_chat_typerõ  rô  )r'   r®   Ú_is_dm_intake_allowedrÝ   rå   ry   r¦  Úlistrd  Ú	enumerater§  Ú_ingest)
r+   rx  rµ  rÌ  rË  rÍ  r  Úattachments_rawÚ_iÚ_atts
   &&&&&&    r-   Ú_handle_c2c_messageÚQQAdapter._handle_c2c_messageã  s/  é € Ü˜&Ÿ*™* ]°BÓ7Ó8ˆß $×"<Ñ"<¸[×"IÒ"IÙàŸ%™% Ó.ˆÜ�‰Ø?Ø�M‰M˜6¶7 7¨3¦<Àß[j¤z°/Ä4×'HÒ'HŒs�?Ô#ÈaÐPÐPVÑWÐpvô	
÷
 œz¨/¼4×@Ò@Ü% oÖ6‘�Ü˜d¤D×)Ô)Ü—K‘KØQØŸ™ r¯8©8°NÀBÓ+GÜ˜DŸH™H U¨BÓ/Ó0°Õ5°t·x±xÀ
ÈBÓ7OöQñ 7ð �l‰lØ�w°ÀDØ¨e¸[ÐTXð ó Z÷ 	Zô 	Zùs*   ‚:F½AFÂ3FÂ99FÃ7BFÅ:FÅ;Fc               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs   ú  s   € ÷ [ñ [ÐTXñ [r/   c              ƒ  	ó>  "  € \        VP                  R R4      4      p\        VP                  RR4      4      pV'       d   V P                  Wg4      '       g   R# V P                  WV P	                  V4      VP                  R4      VVRVRR7	      G Rj  x€L
  R#  L5i)r  r#   Úmember_openidNr+  r   ©rÄ  r3  rõ  rô  )r'   r®   Ú_is_group_allowedr7  Ú_strip_at_mention)r+   rx  rµ  rÌ  rË  rÍ  r  Úmembers   &&&&&&  r-   Ú_handle_group_messageÚQQAdapter._handle_group_messageú  sŠ   é € Ü˜1Ÿ5™5 °Ó4Ó5ˆÜ�V—Z‘Z °Ó4Ó5ˆß 4×#9Ñ#9¸,×#OÒ#OÙØ�l‰lØ�t×-Ñ-¨gÓ6¸¿¹¸mÓ8LÈiØ ¨wÀÐRYð ó [÷ 	[ô 	[ùs   ‚BBÂBÂBc               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs     s   € ÷ tñ tÐTXñ tr/   c              ƒ  	ó°  "  € \        VP                  R R4      4      pV'       g   R# \        VP                  RR4      4      p\        VP                  RR4      4      pT P                  T;'       g    TV4      '       g$   \        P	                  RV P
                  Wh4       R# \        VP                  R4      \        4      '       d   VP                  R4      M/ p	\        V	P                  RR4      4      ;'       g    \        VP                  RR4      4      p
T P                  YY1P                  R	4      TTR
YŠ;'       g    RRR7
      G Rj  x€L
  R#  L5i)Ú
channel_idr#   Nr  rÊ  z5[%s] Guild message blocked by ACL: channel=%s user=%srC  ÚnickÚusernamer+  r  r   )rÄ  r3  rõ  Ú	user_namerô  )	r'   r®   rA  rÝ   r|  ry   r¦  r§  r7  )r+   rx  rµ  rÌ  rË  rÍ  rH  r  Ú	author_idrC  rI  s   &&&&&&     r-   Ú_handle_guild_messageÚQQAdapter._handle_guild_message  s  é € Ü˜Ÿ™˜|¨RÓ0Ó1ˆ
ßÙô �q—u‘u˜Z¨Ó,Ó-ˆÜ˜Ÿ
™
 4¨Ó,Ó-ˆ	Ø×%Ñ% h×&<Ð&<°*¸i×HÒHÜ�L‰LÐPÐRV×R_ÑR_ÐakÔwÙä$.¨q¯u©u°X«Ä×$EÒ$E�—‘�x”È2ˆÜ�6—:‘:˜f bÓ)Ó*×MÐM¬c°&·*±*¸ZÈÓ2LÓ.MˆØ�l‰lØ�w§¡ mÓ 4°iØ¨W¸i×S_ÐS_Ð[_Ðkrð ó t÷ 	tô 	tùs&   ‚A/EÁ2EÂ A<EÃ=AEÅEÅEc               ó   € V ^8„  d   QhRR/# rˆ   rb   )rc   s   "r-   rd   rs     s   € ÷ Tñ TÐQUñ Tr/   c              ƒ  	ód  "  € \        VP                  R R4      4      pV'       g   R# \        VP                  RR4      4      pV P                  V4      '       g$   \        P	                  RV P
                  Wg4       R# V P                  WW1P                  R4      VVRVRR7	      G Rj  x€L
  R#  L5i)r  r#   NrÊ  z.[%s] Guild DM blocked by ACL: guild=%s user=%sr+  rþ  r@  )r'   r®   r4  rÝ   r|  ry   r7  )r+   rx  rµ  rÌ  rË  rÍ  r  rL  s   &&&&&&  r-   Ú_handle_dm_messageÚQQAdapter._handle_dm_message  s–   é € Ü�q—u‘u˜Z¨Ó,Ó-ˆßÙä˜Ÿ
™
 4¨Ó,Ó-ˆ	Ø×)Ñ)¨)×4Ò4Ü�L‰LÐIÈ4Ï=É=ÐZbÔnÙØ�l‰lØ�w§¡ mÓ 4°iØ¨4¸Èdð ó T÷ 	Tô 	Tùs   ‚B%B0Â'B.Â(B0ÚC2C_MESSAGE_CREATEr;  ÚGROUP_AT_MESSAGE_CREATErD  ÚGUILD_MESSAGE_CREATErM  ÚGUILD_AT_MESSAGE_CREATEÚDIRECT_MESSAGE_CREATErQ  c               ó$   € V ^8„  d   QhRRRRRR/# )r_   ré  r'   Úblockr`   rb   )rc   s   "r-   rd   rs   ,  s&   € ÷ Jñ J˜Cð J¨ð J°ñ Jr/   c                ón   € V P                  4       '       d   V R,           V,           P                  4       # T# )zUAppend *block* to *text* after a blank line (or return block alone if text is blank).ú

©r°   )ré  rY  s   &&r-   Ú_append_blockÚQQAdapter._append_block+  s+   € ð 37·*±*·,²,��v• Õ%×,Ñ,Ó.ÐIÀEÐIr/   r2  c               ó@   € V ^8„  d   QhRRRRRRRRRRR	RR
RRRRRRR/
# )r_   rx  r  rµ  r'   rÌ  r+  r   rÍ  rÄ  r3  r2  ra   Úsource_kwargsr`   r|   rb   )rc   s   "r-   rd   rs   0  s\   € ÷ )ñ )Øð)Ø),ð)Ø7:ð)ØILð)ØY\ð)àð)à$'ð)à26ð)àQTð)àY]ñ)r/   c             ‹  ól  "  € V P                  V4      G Rj  x€L
 p
TpV
R,          pV'       d"   V P                  VRP                  V4      4      pV
R,          '       d   V P                  WºR,          4      pV
R,          V
R,          ríV'       d5   \        P	                  RV P
                  \        V4      \        V4      4       V P                  V4      G Rj  x€L
 pV P                  W¿R,          4      pVR,          '       d   WßR,          ,           pWïR,          ,           pVP                  4       '       g   V'       g   R# WpP                  V&   \        V P                  ! RR	V/V	B VV P                  WÞ4      VW-VV P                  V4      R
7      pV P                  V4      G Rj  x€L
  R#  EL– L× L5i)z—Shared inbound tail: fold attachment transcripts/file info and quoted context
into the text, drop empty events, remember the QQ chat kind and dispatch.NÚvoice_transcriptsÚ
Úattachment_infoÚ
image_urlsÚimage_media_typesz*[%s] After processing: images=%d, voice=%dÚquote_blockrÄ  )rÃ  ré  Úmessage_typeÚraw_messagerÂ  Ú
media_urlsÚmedia_typesrÍ  rb   )Ú_process_attachmentsr]  ÚjoinrÝ   rå   ry   rd  Ú_process_quoted_contextÚ_merge_quote_intor°   rÀ   r   r  Ú_detect_message_typeÚ_parse_qq_timestamprÅ  )r+   rx  rµ  rÌ  r+  rÍ  rÄ  r3  r2  r`  Úattré  rb  re  rf  ÚquotedrÀ  s   &&&&&&$$$,       r-   r7  ÚQQAdapter._ingest0  s€  é € ð
 ×-Ñ-¨kÓ:×:ˆØˆØÐ 3Õ4ÐßØ×%Ñ% d¨D¯I©IÐ6GÓ,HÓIˆDØÐ ×!Ô!Ø×%Ñ% dÐ0AÕ,BÓCˆDØ(+¨LÕ(9¸3Ð?RÕ;SÐ%ßÜ�K‰KÐDÀdÇmÁmÔUXÐYcÓUdÔfiÐj{Óf|Ô}à×3Ñ3°AÓ6×6ˆØ×%Ñ% d°=Õ,AÓBˆØ�,×ÔØ#¨\Õ&:Õ:ˆJØ 1Ð;NÕ4OÕ OÐØ�z‰z�|Š|§JÙà'3×Ñ˜GÑ$ÜØ×$Ò$ÑF¨WÐF¸ÑFÈTØ×2Ñ2°:ÓQÐ_`ØÐBSØ×.Ñ.¨yÓ9ô	
ˆð ×!Ñ! %Ó(×(Ò(ò5 ;ñ 7ñ 	)ùsM   ‚F4—F-˜F4¯/F4ÁA9F4ÃF0ÃAF4Ä8F4Å A&F4Æ&F2Æ'F4Æ0F4Æ2F4c               ó    € V ^8„  d   QhRRRR/# )r_   rx  r  r`   rb   )rc   s   "r-   rd   rs   S  s   € ÷  Lñ  L¨~ð  LÀ.ñ  Lr/   c           	   ƒ  óˆ  "  € RRR. R. /p \        VP                  R^ 4      ;'       g    ^ 4      ^g8H  pVP                  R4      pV'       d   \	        V\
        4      '       d	   V'       g   V# V Uu. uF  p\	        V\        4      '       g   K  VNK  	  ppR V 4        Uu. uF  qf'       g   K  VNK  	  ppV UUu. uFT  p\	        VP                  R	4      \
        4      '       g   K*  VR	,           F  p\	        V\        4      '       g   K  VNK  	  KV  	  p	ppV P                  V	4      G R
j  x€L
 p
V
P                  R4      ;'       g    . pV'       d   RP                  V4      .M. pTP                  V
P                  R4      ;'       g    . 4       V
P                  R4      '       d   VP                  V
R,          4       V'       g   V'       g   V# RV'       d   RRP                  V4      ,           MRRTRV
P                  R4      ;'       g    . /#   \        \        3 d    Rp EL÷i ; iu upi u upi u uppi  EL5i)af  Process the quoted message a user is replying to (``message_type == 103``;
referenced content + attachments live in ``msg_elements``). Quoted attachments
go through _process_attachments so quoted voice gets STT and quoted images are
cached identically. Returns ``{"quote_block", "image_urls", "image_media_types"}``;
quote_block is "" when nothing is quoted.rg  r#   re  rf  rh  FÚmsg_elementsc              3  ót   "  € T F.  p\        VP                  R R4      4      P                  4       x € K0  	  R# 5i)rÌ  r#   N)r'   r®   r°   )r5  Úes   & r-   r7  Ú4QQAdapter._process_quoted_context.<locals>.<genexpr>c  s.   é € Ð(]ÑT\Èq¬¨Q¯U©U°9¸bÓ-AÓ)B×)HÑ)H×)JÐ)JÓT\ùs   ‚68r+  NÚ rb  rd  z[Quoted message]:
rc  z[Quoted message]: (image))r%   r®   Ú	TypeErrorÚ
ValueErrorr¦  r5  r§  rl  rm  ÚextendÚappend)r+   rx  ÚemptyÚis_quoteÚelementsry  r   Úquoted_text_partsÚaÚall_attachmentsÚ
att_resultÚquoted_imagesÚliness   &&           r-   rn  Ú!QQAdapter._process_quoted_contextS  sô  é € ð   L°"Ð6IÈ2ÐNˆð	Ü˜1Ÿ5™5 °Ó3×8Ð8°qÓ9¸SÑ@ˆHð —5‘5˜Ó(ˆßœz¨(´D×9Ò9ÇØˆLá'Ó?™x˜!¬:°a¼×+>—A�A™xˆÐ?Ù(]ÑT\Ô(]ÓcÑ(] 1ÓabŸQ˜QÑ(]ÐÐcáô|Ù�!¤:¨a¯e©e°MÓ.BÄD×#IŒAÐSTÐUb×ScÐScÈaÔgqÐrsÔuy×gz�AˆAÑSc‰A‘xð 	ñ |à×4Ñ4°_ÓE×Eˆ
Ø"Ÿ™ |Ó4×:Ð:¸ˆç<M˜CŸH™HÐ%6Ó7Ñ8ÐSUˆØ�‰�Z—^‘^Ð$7Ó8×>Ð>¸BÔ?Ø�>‰>Ð+×,Ò,Ø�L‰L˜Ð$5Õ6Ô7ßŸ]ØˆLð ÇuÐ0°4·9±9¸UÓ3CÖCÐRmØ˜-Ø §¡Ð0CÓ!D×!JÐ!JÈðLð 	Løô) œ:Ð&ô 	Ø‹Hð	üò @ùÚcùó|âEùs«   ‚	IŒ(H ´IÁIÁ+IÁ1H/ÂH/ÂIÂ!	H4Â/H4Â5IÂ<'H9Ã(H9Ä
H9ÄIÄ-H?Ä.IÅ

IÅ6IÆIÆ*IÇ
IÇ
IÇ3IÈIÈH,È(IÈ+H,È,Ic               ó$   € V ^8„  d   QhRRRRRR/# )r_   ré  r'   rg  r`   rb   )rc   s   "r-   rd   rs   v  s&   € ÷ Sñ S ð S°#ð S¸#ñ Sr/   c                óp   € V'       g   V # V P                  4       '       d   V RV  2P                  4       # T# )z=Prepend ``quote_block`` to *text*, separated by a blank line.r[  r\  )ré  rg  s   &&r-   ro  ÚQQAdapter._merge_quote_intou  s5   € ÷ ØˆKØ59·Z±Z·\²\�+�˜d 4 &Ð)×/Ñ/Ó1ÐRÀ{ÐRr/   c               ó    € V ^8„  d   QhRRRR/# )r_   rj  r5  rk  rb   )rc   s   "r-   rd   rs     s   € ÷  ñ  ¨ð  ¸Dñ  r/   c                	ó�  € V '       g   \         P                  # V'       g   \         P                  # V^ ,          P                  4       pRV9   g   RV9   g   RV9   d   \         P                  # RV9   d   \         P
                  # RV9   g   RV9   d   \         P                  # \        P                  RV4       \         P                  # )é    ÚaudioÚvoiceÚsilkÚvideoÚimageÚphotoz3Unknown media content_type '%s', defaulting to TEXT)r   rl  ÚPHOTOr³   ÚVOICEÚVIDEOrÝ   r|  )rj  rk  Ú
first_types   && r-   rp  ÚQQAdapter._detect_message_type~  sž   € çÜ×#Ñ#Ð#ßÜ×$Ñ$Ð$Ø  •^×)Ñ)Ó+ˆ
Ø�jÔ  G¨zÔ$9¸VÀzÔ=QÜ×$Ñ$Ð$Ø�jÔ Ü×$Ñ$Ð$Ø�jÔ  G¨zÔ$9Ü×$Ñ$Ð$Ü�‰ÐJÈJÔWÜ×ÑÐr/   c               ó    € V ^8„  d   QhRRRR/# )r_   r+  r   r`   r  rb   )rc   s   "r-   rd   rs   Ž  s   € ÷ 8=ñ 8=°cð 8=¸nñ 8=r/   c           
   ƒ  óV  a a"  € . p. p. p. p\        V\        4      '       d   TMR# EF™  o\        S\        4      '       g   K  \        SP	                  RR4      4      P                  4       P                  4       p\        SP	                  RR4      4      P                  4       p\        SP	                  RR4      4      pV'       g   K¡  VP                  R4      '       d   RV 2p\        P                  RS P                  WgR,          V4       S P                  Wh4      '       d¦   VV 3R	 lR
 4       w  ršS P                  WvW‰V
R
7      G Rj  x€L
 pV'       d7   VP                  RV 24       \        P                  RS P                  V4       M9\        P                  RS P                  VR,          4       VP                  R4       EK¢  VP                  R4      p S P                  WvV4      G Rj  x€L
 pT'       g   EKÙ  T'       gD   TP                  R4      '       d   RMRpTP                  RT RT;'       g    T RT R24       EK$  \"        P$                  P'                  T4      '       d0   TP                  T4       TP                  T;'       g    R4       EKx  \        P                  RS P                  T4       EKœ  	  RVRVR VR!R"P)                  V4      /#  EL” Lð  \          d9   p\        P                  RS P                  T'       d   RMRT4        Rp?EKú  Rp?ii ; i5i)$zÝProcess inbound attachments uniformly. Returns ``{"image_urls",
"image_media_types", "voice_transcripts", "attachment_info"}`` (cached image
paths + MIME types, "[Voice] ..." transcripts, text description of other files).r.  r#   r)  r1  ú//úhttps:z@[%s] Processing attachment: content_type=%s, url=%s, filename=%sr/  c              3  ód   <"  € T F%  pSP                  SP                  V4      4      x € K'  	  R # 5irf   )Ú_opt_strr®   )r5  Úkrr  r+   s   & €€r-   r7  Ú1QQAdapter._process_attachments.<locals>.<genexpr>¦  s'   øé € Ð%mÑIlÀA d§m¡m°C·G±G¸A³J×&?Ð&?ÓIlùs   ƒ-0)Úasr_refer_textÚvoice_wav_urlNz[Voice] z[%s] Voice transcript: %sz[%s] Voice STT failed for %sºNr  Nu   [Voice] [è¯­éŸ³è¯†åˆ«å¤±è´¥]úimage/z[%s] Failed to cache %s: %sr”  Ú
attachmentzvideo/r“  ÚfileÚ[r  ú (z)]z
image/jpegz)[%s] Cached image path does not exist: %sre  rf  rb  rd  rc  rb   )r¦  r5  r§  r'   r®   r°   r³   Ú
startswithrÝ   r|  ry   Ú_is_voice_content_typeÚ_stt_voice_attachmentr  rÞ   Ú_download_and_cacherç   rD  ÚpathÚisfilerm  )r+   r+  re  rf  rb  Úother_attachmentsÚctr)  r1  Ú	asr_referÚwav_urlÚ
transcriptÚis_imageÚcached_pathrï   Úlabelrr  s   f&              @r-   rl  ÚQQAdapter._process_attachmentsŽ  s¬  ùé € ð !#ˆ
Ø')ÐØ')ÐØ')Ðä",¨[¼$×"?Ò"?‘;ÀRÓGˆCÜ˜c¤4×(Ò(ÙÜ�S—W‘W˜^¨RÓ0Ó1×7Ñ7Ó9×?Ñ?ÓAˆBÜ�c—g‘g˜e RÓ(Ó)×/Ñ/Ó1ˆCÜ˜3Ÿ7™7 :¨rÓ2Ó3ˆHßÙØ�~‰~˜d×#Ò#Ø˜s˜e�n�Ü�L‰LØRØ—‘˜r s¥8¨Xô7ð ×*Ñ*¨2×8Ò8Ý%mÑIlÓ%mÑ"�	Ø#'×#=Ñ#=Ø˜XÈwð $>ó $X÷ X�
çØ%×,Ñ,¨x¸
°|Ð-DÔEÜ—L‘LÐ!<¸d¿m¹mÈZÕXä—N‘NÐ#AÀ4Ç=Á=ÐRUÐVYÕRZÔ[Ø%×,Ñ,Ð-KÔLÚà—}‘} XÓ.ˆHðØ$(×$<Ñ$<¸SÀhÓ$O×O�÷ ÚßØ#%§=¡=°×#:Ò#:™À�Ø!×(Ñ(¨1¨U¨G°2°h·n°nÀ"Ð5EÀRÈÀ}ÐTVÐ)W×XÜ—‘—‘ ×,Ò,Ø×!Ñ! +Ô.Ø!×(Ñ(¨×);Ð);¨|×<ä—‘ÐJÈDÏMÉMÐ[f×gñS HðX ˜*ØÐ!2ØÐ!2Ø˜tŸy™yÐ):Ó;ð	=ð 	=ò7Xñ PøÜô Ü—‘Ð:¸D¿M¹M×V^É7ÐdpÐruÔvÞûðüs�   „CL)ÃA+L)Å
KÅL)ÅBL)ÇK#Ç0K!Ç1K#Ç5L)Ç=
L)ÈL)ÈL)È;4L)É0$L)ÊA
L)Ë!K#Ë#L&Ë.,L!ÌL)Ì!L&Ì&L)c               ó    € V ^8„  d   QhRRRR/# )r_   Úvaluer   r`   úOptional[str]rb   )rc   s   "r-   rd   rs   É  s   € ÷ Iñ I˜ð I ñ Ir/   c                	óf   € \        V \        4      '       d   V P                  4       MR ;'       g    R# )r#   N)r¦  r'   r°   )r»  s   &r-   r   ÚQQAdapter._opt_strÈ  s$   € ä!+¨E´3×!7Ò!7�—‘”¸R×HÐHÀDÐHr/   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r_   r)  r'   r.  Úoriginal_namer`   r¼  rb   )rc   s   "r-   rd   rs   Ì  s0   € ÷ Eñ E¨Sð EÀð EÐTWð EÐanñ Er/   c              ƒ  óL  "  € ^ RI Hp V! V4      '       g   \        RVR,           24      hV P                  '       g   R#  V P                  P	                  VRV P                  4       R7      G Rj  x€L
 pVP                  4        VP                  pTP                  R4      '       d-   \        TR	R
RR7      ;'       g    Rp\        Yh4      G Rj  x€L
 # TR8X  g   TP                  R4      '       d   T P                  Ya4      G Rj  x€L
 # T;'       g3    \!        \#        T4      P$                  4      P&                  ;'       g    Rp	\)        Yi4      G Rj  x€L
 #  Lé  \         d5   p\        P                  RT P                  TR,          T4        Rp?R# Rp?ii ; i LÎ L™ LL5i)zWDownload a URL and cache it locally (``original_name`` falls back to the URL basename).©Úis_safe_urlzBlocked unsafe URL: r/  Nr¨   )r  r&  z[%s] Download failed for %s: %sr¦  FTz.jpg)Úuse_defaultsÚuse_mimetypesÚfallbackr‘  úaudio/Úqq_attachment)Útools.url_safetyrÃ  r}  rº   r®   Ú_qq_media_headersr  rÌ  rç   rÝ   r|  ry   r«  r   r   Ú_convert_audio_to_wavr   r   r¯  rÎ   r   )
r+   r)  r.  rÀ  rÃ  r  r  rï   Úextr1  s
   &&&&      r-   r®  ÚQQAdapter._download_and_cacheÌ  s`  é € å0á˜3×ÒÜÐ3°C¸µH°:Ð>Ó?Ð?Ø× × Ð Ùð	Ø×*Ñ*×.Ñ.¨s¸DÈ$×J`ÑJ`ÓJbÐ.Óc×cˆDØ×!Ñ!Ô#Ø—<‘<ˆDð
 ×"Ñ" 8×,Ò,ä˜|¸%ÈtÐ^dÔe×oÐoÐioˆCÜ5°dÓ@×@Ð@Ø˜7Ô" l×&=Ñ&=¸h×&GÒ&Gà×3Ñ3°DÓ>×>Ð>Ø ×TÐT¤D¬°#«×);Ñ);Ó$<×$AÑ$A×TÐTÀ_ˆÜ4°TÓD×DÐDñ døô ô 	Ü�L‰LÐ:¸D¿M¹MÈ3ÈsÍ8ÐUXÔYÝûð	úñ Añ ?áDùs”   ‚;F$¾F$Á/E Á0EÁ1 E ÂF$Â(F$Â>F$ÃFÃ!F$Ã2F$ÄF ÄF$Ä/F$ÅF$ÅF"ÅF$ÅE ÅFÅ')FÆF$ÆFÆF$Æ F$Æ"F$c               ó$   € V ^8„  d   QhRRRRRR/# )r_   r.  r'   r1  r`   ra   rb   )rc   s   "r-   rd   rs   ç  s&   € ÷ Dñ D¨Sð D¸Cð DÀDñ Dr/   c                	óò   € V P                  4       P                  4       pVR 8X  g   VP                  R4      '       d   R# VR8X  d   R# VP                  4       P                  4       P                  \        4      # )r‘  rÇ  Tr¨  F)r°   r³   r«  ÚendswithÚ_VOICE_EXTENSIONS)r.  r1  r²  s   && r-   r¬  Ú QQAdapter._is_voice_content_typeæ  s]   € à×ÑÓ!×'Ñ'Ó)ˆØ�Œ=˜BŸM™M¨(×3Ò3Ùà�Œ<ÙØ�~‰~Ó×%Ñ%Ó'×0Ñ0Ô1BÓCÐCr/   c               ó   € V ^8„  d   QhRR/# ©r_   r`   zdict[str, str]rb   )rc   s   "r-   rd   rs   ð  s   € ÷ ^ñ ^ >ñ ^r/   c                óL   € V P                   '       d   RRV P                    2/# / # )zNAuthorization header for QQ multimedia CDN downloads (required, else non-200).r#  r$  )rÄ   r�   s   &r-   rÊ  ÚQQAdapter._qq_media_headersð  s,   € àCG×CU×CUÐCU� 6¨$×*<Ñ*<Ð)=Ð!>Ð?Ð]Ð[]Ð]r/   r£  Nr¤  c               ó0   € V ^8„  d   QhRRRRRRRRRRRR/# )	r_   r)  r'   r.  r1  r£  r¼  r¤  r`   rb   )rc   s   "r-   rd   rs   ô  s<   € ÷ >ñ >Øð>Ø&)ð>Ø58ð>ØMZð>à$ð>à0=ñ>r/   c          	   ƒ  óÖ  "  € V'       d+   \         P                  RV P                  VR,          4       V# \        V4      pTpV'       d?   VP	                  R4      '       d   RV 2MTp\         P                  RV P                  4       ^ RIHp V! V4      '       g    \         P                  RVR,          4       R	#  V P                  '       g#   \         P                  R
V P                  4       R	# V P                  4       p	\         P                  RV P                  VR,          V\        V	4      4       V P                  P                  VRV	RR7      G R	j  x€L
 p
V
P                  4        V
P                  p\         P                  RV P                  \        V4      V
P                  P                  RR4      4       \        V4      ^
8  d-   \         P                  RV P                  \        V4      4       R	# V'       d>   V P                  VR4      p\         P                  RV P                  \        V4      4       Mƒ\         P                  RV P                  V4       V P!                  W³4      G R	j  x€L
 pV'       d    \#        V4      P%                  4       '       g#   \         P                  RV P                  4       R	# \         P                  RV P                  V4        V P'                  V4      G R	j  x€L
 pV P)                  V4       V'       d+   \         P                  RV P                  VR,          4       V# \         P                  RV P                  4       V#  EL
 Lð Ln  T P)                  T4       i ; i  \*        \,        P.                  \,        P0                  3 dA   p\         P                  RT P                  \3        T4      P4                  T4        R	p?R	# R	p?ii ; i5i)uÐ   Transcribe a voice attachment. Priority: QQ's free ``asr_refer_text`` â†’
STT on ``voice_wav_url`` (pre-converted WAV, no SILK decode) â†’ STT on the
original URL (SILKâ†’WAV). Returns the transcript or None.z%[%s] STT: using QQ asr_refer_text: %r:Néd   Nr�  rž  z1[%s] STT: using voice_wav_url (pre-converted WAV)rÂ  z[QQ] STT blocked unsafe URL: %sr/  Nz[%s] STT: no HTTP clientz<[%s] STT: downloading voice from %s (pre_wav=%s, headers=%s)r¨   T)r  r&  Úfollow_redirectsz.[%s] STT: downloaded %d bytes, content_type=%szcontent-typeÚunknownz8[%s] STT: downloaded data too small (%d bytes), skippingú.wavz5[%s] STT: using pre-converted WAV directly (%d bytes)z([%s] STT: converting to wav, filename=%rz.[%s] STT: ffmpeg conversion produced no outputz[%s] STT: calling ASR on %sz[%s] STT success: %rz'[%s] STT: ASR returned empty transcriptz,[%s] STT failed for voice attachment: %s: %s)rÝ   r|  ry   ra   r«  rÉ  rÃ  rÞ   rº   rÊ  r®   r  rÌ  rd  r&  Ú_write_tempÚ_convert_audio_to_wav_filer   ÚexistsÚ	_call_sttÚ_unlink_quietÚOSErrorÚhttpxÚHTTPStatusErrorÚTransportErrorrj  r1   )r+   r)  r.  r1  r£  r¤  Ú
is_pre_wavÚdownload_urlrÃ  Údownload_headersr  Ú
audio_dataÚwav_pathrµ  rï   s   &&&&$$         r-   r­  ÚQQAdapter._stt_voice_attachmentô  s	  é € ÷ Ü�L‰LÐ@À$Ç-Á-ÐQ_Ð`dÕQeÔfØ!Ð!ä˜-Ó(ˆ
ØˆßØ7D×7OÑ7OÐPT×7UÒ7U˜V M ?Ñ3Ð[hˆLÜ�L‰LÐLÈdÏmÉmÔ\å0Ù˜<×(Ò(Ü�N‰NÐ<¸lÈ3Õ>OÔPÙð)	Ø×$×$Ð$Ü—‘Ð9¸4¿=¹=ÔIÙØ#×5Ñ5Ó7ÐÜ�L‰LØNØ—‘˜|¨CÕ0°*¼dÐCSÓ>TôVð ×*Ñ*×.Ñ.Ø dÐ4DÐW[ð /ó ]÷ ]ˆDà×!Ñ!Ô#ØŸ™ˆJÜ�L‰LØ@Ø—‘œs :›°·±×0@Ñ0@ÀÐQZÓ0[ô]ô �:‹ Ô#Ü—‘ÐYÐ[_×[hÑ[hÔjmÐnxÓjyÔzÙçØ×+Ñ+¨J¸Ó?�Ü—‘ÐTÐVZ×VcÑVcÔehÐisÓetÕuä—‘ÐGÈÏÉÐX`ÔaØ!%×!@Ñ!@ÀÓ!V×V�ß¤t¨H£~×'<Ñ'<×'>Ò'>Ü—N‘NÐ#SÐUY×UbÑUbÔcÙä�L‰LÐ6¸¿¹ÀxÔPð-Ø#'§>¡>°(Ó#;×;�
à×"Ñ" 8Ô,ßÜ—‘Ð3°T·]±]ÀJÈtÕDTÔUð Ðô —‘ÐHÈ$Ï-É-ÔXØÐò=]ñ  Wñ <øà×"Ñ" 8Õ,ûô œ×.Ñ.´×0DÑ0DÐEô 	Ü�N‰NÐIÈ4Ï=É=ÔZ^Ð_bÓZc×ZlÑZlÐnqÔrÝûð	üsÕ   ‚AO)Á!:O)ÂO)Â<M< Ã M< Ã.O)Ã0A%M< ÅMÅBM< Ç5O)Ç7M< Ç?A2M< É1M"É2M< É>?M< Ê=O)Ê?!M< Ë!M& Ë5M$Ë6M& Ë:M< Ì)M< Ì<O)Ì=!M< ÍO)ÍM< Í"M< Í$M& Í&M9Í9M< Í<*O&Î&5O!ÏO)Ï!O&Ï&O)c               ó$   € V ^8„  d   QhRRRRRR/# )r_   r  ÚbytesÚsuffixr'   r`   rb   )rc   s   "r-   rd   rs   5  s!   € ÷ ñ ˜%ð ¨ð °ñ r/   c                ó¸   € ^ RI pVP                  VRR7      ;_uu_ 4       pVP                  V 4       VP                  uuRRR4       #   + '       g   i     R# ; i)zDWrite *data* to a persistent NamedTemporaryFile and return its path.NF)rî  Údelete)ÚtempfileÚNamedTemporaryFileÚwriterÎ   )r  rî  rñ  r'  s   &&  r-   rÝ  ÚQQAdapter._write_temp4  sA   € ó 	à×(Ñ(°¸uÐ(×EÔEÈØ�I‰I�dŒOØ—8‘8÷ F×E×EÓEús    AÁA	c               ó    € V ^8„  d   QhRRRR/# )r_   r¯  r'   r`   r|   rb   )rc   s   "r-   rd   rs   >  s   € ÷ ñ ˜Cð  Dñ r/   c                	ó°   € \         P                  ! \        4      ;_uu_ 4        \        P                  ! V 4       R R R 4       R #   + '       g   i     R # ; irf   )ry  rz  râ  rD  Úunlink)r¯  s   &r-   rá  ÚQQAdapter._unlink_quiet=  s-   € ä× Ò ¤×)Õ)Ü�IŠI�dŒO÷ *×)×)Ò)ús   £AÁA	c               ó    € V ^8„  d   QhRRRR/# )r_   rê  r'   r`   ra   rb   )rc   s   "r-   rd   rs   C  s   € ÷ Nñ N˜#ð N $ñ Nr/   c                ó�   € \        V 4      P                  4       ;'       d'    \        V 4      P                  4       P                  ^,8„  # )zFTrue when *wav_path* exists and holds more than a bare 44-byte header.)r   rß  ÚstatÚst_size)rê  s   &r-   Ú_wav_okÚQQAdapter._wav_okB  s7   € ô �H‹~×$Ñ$Ó&×MÐM¬4°«>×+>Ñ+>Ó+@×+HÑ+HÈ2Ñ+MÐMr/   c               ó$   € V ^8„  d   QhRRRRRR/# )r_   ré  rí  rÌ  r'   r`   ztuple[str, str]rb   )rc   s   "r-   rd   rs   H  s!   € ÷ =ñ = Eð =°ð =¸ñ =r/   c                óf   € V P                  W4      pW3P                  R^4      ^ ,          R,           3# )zWWrite *audio_data* to a temp ``<x>{ext}`` and return ``(src_path, sibling .wav path)``.Ú.rÜ  )rÝ  Úrsplit)Úclsré  rÌ  Úsrc_paths   &&& r-   Ú
_temp_pairÚQQAdapter._temp_pairG  s0   € ð —?‘? :Ó3ˆØŸ™¨¨aÓ0°Õ3°fÕ<Ð<Ð<r/   c               ó$   € V ^8„  d   QhRRRRRR/# )r_   ré  rí  r1  r'   r`   r¼  rb   )rc   s   "r-   rd   rs   M  s"   € ÷ ñ ¸5ð ÈCð ÐTañ r/   c              ƒ  óô  "  € \        V4      P                  P                  4       ;'       g    V P                  V4      p\        P                  RV P                  \        V4      W1R,          4       V P                  W4      w  rEV P                  WE4      G Rj  x€L
 ;'       g;    V P                  WE4      G Rj  x€L
 ;'       g    V P                  W4      G Rj  x€L
 pV P                  V4       V#  LY L: L5i)uŒ   Convert audio bytes to a temp .wav: pilk (SILK, which ffmpeg can't decode)
â†’ ffmpeg â†’ raw-PCM last resort. Returns the wav path or None.z7[%s] STT: audio_data size=%d, ext=%r, first_20_bytes=%r:Né   NN)r   rî  r³   Ú_guess_ext_from_datarÝ   rå   ry   rd  r  Ú_convert_silk_to_wavÚ_convert_ffmpeg_to_wavÚ_convert_raw_to_wavrá  )r+   ré  r1  rÌ  r  rê  Úresults   &&&    r-   rÞ  Ú$QQAdapter._convert_audio_to_wav_fileM  sÙ   é € ô �8‹n×#Ñ#×)Ñ)Ó+×TÐT¨t×/HÑ/HÈÓ/TˆÜ�‰ØEØ�M‰Mœ3˜z›?¨C¸Cµô	Bð "Ÿ_™_¨ZÓ=Ñˆà×+Ñ+¨HÓ?×?÷ Dð DØ×0Ñ0°ÓD×D÷Dð Dà×-Ñ-¨jÓC×Cð 	ð 	×Ñ˜8Ô$Øˆñ	 @ÙDÙCùsB   ‚BC8ÂC2Â
C8Â$C8Â9C4Â:
C8ÃC8ÃC6ÃC8Ã4C8Ã6C8c               ó    € V ^8„  d   QhRRRR/# )r_   r  rí  r`   r'   rb   )rc   s   "r-   rd   rs   b  s   € ÷ _ñ _¨ð _°#ñ _r/   c                óD   a€ \        V3R lV P                   4       R4      # )uK   Guess file extension from magic bytes (unknown â†’ .amr, QQ's most common).c              3  ó^   <"  € T F"  w  rSP                  V4      '       g   K  Vx € K$  	  R # 5irf   )r«  )r5  ÚmagicrÌ  r  s   &  €r-   r7  Ú1QQAdapter._guess_ext_from_data.<locals>.<genexpr>d  s    øé € ÐU©?™Z˜U¸d¿o¹oÈe×>T—S’S«?ùs   ƒ-£
-ú.amr)rB  Ú_MAGIC_EXTS©r  r  s   &fr-   r
  ÚQQAdapter._guess_ext_from_dataa  s   ø€ ô ÔU¨3¯?ª?ÓUÐW]Ó^Ð^r/   c               ó    € V ^8„  d   QhRRRR/# )r_   r  rí  r`   ra   rb   )rc   s   "r-   rd   rs   g  s   € ÷ 9ñ 9 Eð 9¨dñ 9r/   c                	ó*   € V P                  V4      R 8H  # )ú.silk)r
  r  s   &&r-   Ú_looks_like_silkÚQQAdapter._looks_like_silkf  s   € à×'Ñ'¨Ó-°Ñ8Ð8r/   c               ó$   € V ^8„  d   QhRRRRRR/# ©r_   r  r'   rê  r`   r¼  rb   )rc   s   "r-   rd   rs   j  s!   € ÷ ñ °3ð À#ð È-ñ r/   c           
   ƒ  ó&  "  €  ^ RI pTP                  R^4      ^ ,          R,           p TRR3TRR33 F¸  w  rVp YT8X  d   ^ RIpTP                  Y4       TP                  YRR	R
7       T P                  T4      '       dm   \        P                  RT P
                  \        T4      P                  T\        T4      P                  4       P                  4       Tu T P!                  T4       # Kº  	  T P!                  T4       R#   \         d1    \        P                  R\	        R4       2T P
                  4        R# i ; i  \"         d.   p	\        P                  RT P
                  Yy4        Rp	?	EK@  Rp	?	ii ; i  T P!                  T4       i ; i5i)zXConvert to WAV with pilk: as-is first, then copied to .silk (pilk checks the extension).Nu;   [%s] pilk not installed â€” cannot decode SILK audio. Run: r’  r  r  r#   Údirectz (as .silk)é€>  )Úratez*[%s] pilk converted %s%s to wav (%d bytes)z"[%s] pilk %s conversion failed: %s)ÚpilkÚImportErrorrÝ   rÞ   r   ry   r  ÚshutilÚcopy2Úsilk_to_wavrý  r|  r   rÎ   rû  rü  rá  rç   )
r+   r  rê  r$  Ú	silk_pathr¯  r¸  Úhowr&  rï   s
   &&&       r-   r  ÚQQAdapter._convert_silk_to_wavj  so  é € ð	Ûð —O‘O C¨Ó+¨AÕ.°Õ8ˆ	ð	*Ø&.°°HÐ%=À	È=ÐZaÐ?bÓ$cÑ �˜Sð`ØÔ(Û%àŸ™ XÔ9Ø×$Ñ$ T¸%Ð$Ô@Ø—|‘| H×-Ò-ÜŸ™ØHØ ŸM™M¬4°«>×+>Ñ+>ÀÄtÈHÃ~×GZÑGZÓG\×GdÑGdôfð  (™ð ×Ñ˜yÕ)ñ .ñ %dð ×Ñ˜yÔ)Ùøô/ ô 	Ü�N‰NÐXÜ*¨6Ó2Ð3ð5Ø6:·m±môEâð	ûô& !ô `Ü—L‘LÐ!EÀtÇ}Á}ÐVY×_Ó_ûð`ûð ×Ñ˜yÕ)üst   ‚F„D ˆ F©E; ºBE ÃE; ÃFÃ+E; Ã/FÄ7D=Ä9FÄ<D=Ä=FÅ E8Å!E3Å,E; Å3E8Å8E; Å;FÆFc               ó$   € V ^8„  d   QhRRRRRR/# )r_   ré  rí  rê  r'   r`   r¼  rb   )rc   s   "r-   rd   rs   ‡  s!   € ÷ ñ °Eð ÀSð È]ñ r/   c              ƒ  ó‚  "  €  ^ RI pVP                  VR4      ;_uu_ 4       pVP                  ^4       VP                  ^4       VP	                  R4       VP                  V4       RRR4       V#   + '       g   i     T# ; i  \         d-   p\        P                  RT P                  T4        Rp?R# Rp?ii ; i5i)z„Last resort: wrap bytes as raw PCM 16-bit mono 16kHz WAV (garbage if not
PCM, but the ASR engine returns empty instead of crashing).NÚwr"  z [%s] raw PCM fallback failed: %s)
ÚwaveÚopenÚsetnchannelsÚsetsampwidthÚsetframerateÚwriteframesrç   rÝ   r|  ry   )r+   ré  rê  r/  Úwfrï   s   &&&   r-   r  ÚQQAdapter._convert_raw_to_wav‡  s’   é € ð	Ûà—‘˜8 S×)Ô)¨RØ—‘ Ô"Ø—‘ Ô"Ø—‘ Ô&Ø—‘˜zÔ*÷	 *ð
 ˆO÷ *Ö)ð
 ˆOûÜô 	Ü�L‰LÐ;¸T¿]¹]ÈCÔPÝûð	üsR   ‚B?„B ¢AA1Á'	B Á0B?Á1B	Á<B ÂB?ÂB ÂB<Â!B7Â1B?Â7B<Â<B?c               ó$   € V ^8„  d   QhRRRRRR/# r  rb   )rc   s   "r-   rd   rs   —  s!   € ÷ ñ °Sð ÀCð ÈMñ r/   c              ƒ  	óT  "  €  \         P                  ! R RRVRRRRV\         P                  P                  \         P                  P                  \         P                  P                  R7      G Rj  x€L
 p\         P
                  ! VP                  4       ^R	7      G Rj  x€L
  VP                  ^ 8w  d…   VP                  '       d#   VP                  P                  4       G Rj  x€L
 MR
p\        P                  RV P                  \        V4      P                  VR,          P                  RR7      4       R#  T P%                  T4      '       g7   \        P                  RT P                  \        T4      P                  4       R# \        P'                  RT P                  \        T4      P                  \        T4      P)                  4       P*                  4       T#  ELn ELC EL  \         \"        3 d-   p\        P                  RT P                  T4        Rp?R# Rp?ii ; i5i)Úffmpegz-yz-iz-arÚ16000z-acÚ1)ÚstdinÚstdoutÚstderrN©r  r/   z[%s] ffmpeg failed for %s: %srã  r%  )Úerrorsz [%s] ffmpeg conversion error: %sz+[%s] ffmpeg produced no/small output for %sz*[%s] ffmpeg converted %s to wav (%d bytes))rÆ   Úcreate_subprocess_execÚ
subprocessÚDEVNULLÚPIPEÚwait_forÚwaitÚ
returncoder>  ÚreadrÝ   rÞ   ry   r   rÎ   ÚdecodeÚTimeoutErrorÚFileNotFoundErrorrý  r|  rû  rü  )r+   r  rê  Úprocr>  rï   s   &&&   r-   r  Ú QQAdapter._convert_ffmpeg_to_wav—  s   é € ð	Ü ×7Ò7Ø˜$  h°°wÀÀsÈHÜ×(Ñ(×0Ñ0¼×9KÑ9K×9SÑ9SÔ\c×\nÑ\n×\sÑ\sôu÷ uˆDô ×"Ò" 4§9¡9£;¸Ô;×;Ð;Ø�‰ !Ô#Ø59·[·[°[˜tŸ{™{×/Ñ/Ó1×1Ð1Àc�Ü—‘Ø3Ø—M‘M¤4¨£>×#6Ñ#6¸¸t½×8KÑ8KÐS\Ð8KÓ8]ô_ñ ð $ð �|‰|˜H×%Ò%Ü�N‰NÐHÈ$Ï-É-ÔY]Ð^fÓYg×YlÑYlÔmÙÜ�‰Ø8Ø�M‰Mœ4 ›>×.Ñ.´°X³×0CÑ0CÓ0E×0MÑ0Mô	Oð ˆò)uò <â1øô
 Ô/Ð0ô 	Ü�N‰NÐ=¸t¿}¹}ÈcÔRÝûð	üss   ‚H(„A-G( Á1GÁ2-G( ÂG"Â &G( ÃG( Ã$G%Ã%AG( Ä7H(ÅBH(ÇG( Ç"G( Ç%G( Ç(H%Ç9!H ÈH(È H%È%H(c               ó   € V ^8„  d   QhRR/# )r_   r`   r°  rb   )rc   s   "r-   rd   rs   ¯  s   € ÷ ñ Ð%=ñ r/   c                ód  € ^ RI HpHp V P                  P                  ;'       g    / P                  R4      p\        V\        4      '       Ed   VP                  R4      RJdý   VP                  R4      ;'       g    VP                  RR4      pVP                  R4      ;'       g    VP                  R	R4      pVP                  R
R4      pV! VRV4      pV'       d,   V'       d$   RVP                  R4      R	TR
T;'       g    RRV/# V'       dP   VP                  RR4      p\        P                  VR4      pV'       d    VR9   d   RMRp	RTR	TR
T;'       g    T	RV/# \        RR4      p
V
'       d=   \        R\        R,          4      p\        RR4      pRVP                  R4      R	V
R
VRV/# R# )a  Resolve STT backend: ``extra["stt"]`` config first, then ``QQ_STT_*`` env
vars; None when unconfigured (QQ's built-in ASR still works). ``timeout`` (seconds,
default 60) follows the shared STT client default so a self-hosted model's cold start
is not cut off at 30s (#112939).)ÚDEFAULT_STT_TIMEOUTÚ_config_numberÚsttÚenabledFÚbaseUrlÚbase_urlr#   ÚapiKeyÚapi_keyÚmodelr  Ú/z	whisper-1Úproviderrj   zglm-asrÚQQ_STT_API_KEYÚQQ_STT_BASE_URLÚQQ_STT_MODELN>   rl   rj   )Útools.transcription_commonrP  rQ  r›   r­   r®   r¦  r§  ÚrstripÚ_STT_PROVIDER_BASE_URLSr¯   )r+   rP  rQ  Ústt_cfgrU  rW  rX  r  rZ  Údefault_modelÚ
qq_stt_keys   &          r-   Ú_resolve_stt_configÚQQAdapter._resolve_stt_config¯  s”  € ÷
 	SØ—;‘;×$Ñ$×*Ð*¨×/Ñ/°Ó6ˆÜ�gœt×$Ó$¨¯©°YÓ)?ÀuÓ)LØ—{‘{ 9Ó-×LÐL°·±¸ZÈÓ1LˆHØ—k‘k (Ó+×IÐI¨w¯{©{¸9ÀbÓ/IˆGØ—K‘K ¨Ó,ˆEÙ$ W¨iÐ9LÓMˆGßŸGØ" H§O¡O°CÓ$8¸)ÀWÈgÐW\×WkÐWkÐ`kØ! 7ð,ð ,çØ"Ÿ;™; z°5Ó9�Ü2×6Ñ6°xÀÓD�ßØ19¸^Ô1K¡IÐQ\�MØ&¨°)¸WÀgÈu×OeÐOeÐXeØ% wð0ð 0ô (Ð(8¸"Ó=ˆ
ßÜ)Ð*;Ô=TÐUZÕ=[Ó\ˆHÜ& ~°yÓAˆEØ §¡°Ó 4°iÀÈWÐV[ØÐ2ð4ð 4ár/   c               ó    € V ^8„  d   QhRRRR/# )r_   rê  r'   r`   r¼  rb   )rc   s   "r-   rd   rs   Î  s   € ÷ ñ ¨ð °ñ r/   c           
   ƒ  ó¬  "  € V P                  4       pV'       g#   \        P                  RV P                  4       R# VR,          VR,          VR,          rTp \	        VR4      ;_uu_ 4       pV P
                  P                  V R2RR	V 2/R
\        V4      P                  VR3/RV/VR,          R7      G Rj  x€L
 pRRR4       XP                  4        VP                  4       pVP                  R. 4      p	V	'       d*   V	^ ,          P                  R/ 4      P                  RR4      MRp
V
P                  4       ;'       g+    VP                  RR4      P                  4       ;'       g    R#  L³  + '       g   i     L¹; i  \        \        P                  3 d5   p\        P                  RT P                  YSR,          T4        Rp?R# Rp?ii ; i5i)zOTranscribe a wav via an OpenAI-compatible STT API; None if unconfigured/failed.z9[%s] STT not configured (no stt config or QQ_STT_API_KEY)NrU  rW  rX  Úrbz/audio/transcriptionsr#  zBearer r¨  z	audio/wavr  )r&  Úfilesr  r  Úchoicesrî   rÌ  r#   ré  z0[%s] STT API call failed (model=%s, base=%s): %sr,  )rd  rÝ   rÞ   ry   r0  rº   r  r   rÎ   r  r  r®   r°   râ  rã  rä  )r+   rê  ra  rU  rW  rX  Úfr  r  rj  rÌ  rï   s   &&          r-   rà  ÚQQAdapter._call_sttÎ  s�  é € à×*Ñ*Ó,ˆßÜ�N‰NÐVÐX\×XeÑXeÔfÙà#*¨:Õ#6¸À	Õ8JÈGÐT[ÕL\˜5ˆð	Ü�h ×%Ô%¨Ø!×.Ñ.×3Ñ3Ø�jÐ 5Ð6Ø,°¸°yÐ.AÐBØ!¤D¨£N×$7Ñ$7¸¸KÐ#HÐIØ! 5Ð)Ø# IÕ.ð 4ó 0÷ 0�÷ &ð ×!Ñ!Ô#Ø—Y‘Y“[ˆFà—j‘j ¨BÓ/ˆGßJQ�g˜a•j—n‘n Y°Ó3×7Ñ7¸	À2ÔFÐWYˆGØ—=‘=“?×LÐL f§j¡j°¸Ó&<×&BÑ&BÓ&D×LÐLÈÐLñ0÷ &×%ûô œ×.Ñ.Ð/ô 	Ü�N‰NÐMÈtÏ}É}Ð^cÐnqÕerÐtwÔxÝûð	üso   ‚AGÁF Á,AE/Â9E-Â:E/Â>AF Ä AF Å'F Å*F Å,GÅ-E/Å/E?	Å:F ÆGÆ)GÇGÇGÇGc               ó$   € V ^8„  d   QhRRRRRR/# )r_   ré  rí  Ú
source_urlr'   r`   r¼  rb   )rc   s   "r-   rd   rs   è  s"   € ÷ ñ °eð Èð ÐQ^ñ r/   c              ƒ  óì  "  € \        \        V4      P                  4      P                  P	                  4       pV\
        9  d   V P                  V4      pV P                  W4      w  rEVR8H  ;'       g    V P                  V4      pV'       d   V P                  MV P                  p V! WE4      G Rj  x€L
 '       gR   \        P                  RV P                  VR,          V4       \        VRV 24      G Rj  x€L
 V P                  V4       #  T P                  T4        \        T4      P#                  4       p\$        P&                  ! T4       \        TR4      G Rj  x€L
 #  L± Lm  \          d-    \        TRT 24      G Rj  x€L 
 u T P                  T4       # i ; i  T P                  T4       i ; i LX  \          d-   p	\        P)                  RT P                  T	4        Rp	?	R# Rp	?	ii ; i5i)z˜Convert audio bytes to .wav (pilk for SILK, else ffmpeg) and cache the result;
on conversion failure the original bytes are cached as ``qq_voice<ext>``.r  Nz/[%s] audio conversion failed for %s (format=%s)r¥  Úqq_voicezqq_voice.wavz%[%s] Failed to read converted wav: %s)r   r   r¯  rî  r³   Ú_AUDIO_URL_EXTENSIONSr
  r  r  r  r  rÝ   rÞ   ry   r   rá  rç   Ú
read_bytesrD  r÷  r|  )
r+   ré  rn  rÌ  r  rê  Úis_silkÚconvertÚwav_datarï   s
   &&&       r-   rË  ÚQQAdapter._convert_audio_to_wavè  sª  é € ô ”8˜JÓ'×,Ñ,Ó-×4Ñ4×:Ñ:Ó<ˆØÔ+Ô+Ø×+Ñ+¨JÓ7ˆCØ!Ÿ_™_¨ZÓ=ÑˆØ˜‘.×EÐE D×$9Ñ$9¸*Ó$Eˆß/6�$×+Ò+¸D×<WÑ<Wˆð	)Ù  Ó4×4Ö4Ü—‘ÐPÐRV×R_ÑR_ÐakÐloÕapÐruÔvÜ<¸ZÈ8ÐTWÐSXÐIYÓZ×Zð ×Ñ˜xÕ(ð 5ð ×Ñ˜xÔ(ð	Ü˜H“~×0Ñ0Ó2ˆHÜ�IŠI�hÔÜ8¸À>ÓR×RÐRñ 5áZøÜô 	WÜ8¸ÀxÐPSÈuÐEUÓV×VÐVÑVà×Ñ˜xÕ(ð	Wûð ×Ñ˜xÕ(úñ
 SøÜô 	Ü�L‰LÐ@À$Ç-Á-ÐQTÔUÝûð	üsÀ   ‚A1G4Á4G4ÂG4Â'E( Â2E$Â3	E( Â=;E( Ã8E&Ã9E( Ã<G4ÄG4Ä!>F: ÅF8Å F: Å#G4Å$E( Å&E( Å(FÆFÆFÆF" ÆG4ÆFÆF" Æ"F5Æ5G4Æ8F: Æ:G1Ç!G,Ç&G4Ç,G1Ç1G4c               ó   € V ^8„  d   QhRR/# )r_   r`   zhttpx.AsyncClientrb   )rc   s   "r-   rd   rs     s   € ÷ !ñ !Ð&7ñ !r/   c                	óT   € V P                   '       g   \        R 4      hV P                   # )u.   HTTP client not initialized â€” not connected?)rº   r‚   r�   s   &r-   rå  ÚQQAdapter._require_http_client  s&   € Ø× × Ð ÜÐOÓPÐPØ× Ñ Ð r/   c          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r_   Úmethodr'   r¯  Úbodyr°  r  Úfloatr`   r  rb   )rc   s   "r-   rd   rs   	  s;   € ÷ Oñ OØðOØ!$ðOØ,DðOØV[ðOà	ñOr/   c              ƒ  	ó®  "  € V P                  4       pV P                  4       G R j  x€L
 p VP                  V\         V 2WcVR7      G R j  x€L
 pVP	                  4       pVP
                  R8¼  d/   \        RVP
                   RV RVP                  RV4       24      hV#  L{ LW  \        P                   d   p	\        RT RT	 24      T	hR p	?	ii ; i5i)	Nrà  rá  zQQ Bot API error [z] r  rî   zQQ Bot API timeout [râ  )
rå  rç  r  r9   r  rè  r‚   r®   rã  ÚTimeoutException)
r+   r{  r¯  r|  r  Úclientr&  r  r  rï   s
   &&&&&     r-   Ú_api_requestÚQQAdapter._api_request	  sá   é € ð ×*Ñ*Ó,ˆØ×*Ñ*Ó,×,ˆð	OØŸ™¨´8°*¸T¸FÐ0CÈWÐip˜Óq×qˆDØ—9‘9“;ˆDØ×Ñ 3Ô&Ü"Ð%7¸×8HÑ8HÐ7IÈÈDÈ6ÐQSÐTX×T\ÑT\Ð]fÐhlÓTmÐSnÐ#oÓpÐpØˆKñ -áqøô
 ×%Ñ%ô 	OÜÐ!5°d°V¸3¸s¸eÐDÓEÈ3ÐNûð	OüsE   ‚$C¦B"§C¬ B& ÁB$ÁAB& Â!CÂ$B& Â&CÂ;CÃCÃCc               ó   € V ^8„  d   QhRR/# rÔ  rb   )rc   s   "r-   rd   rs     s   € ÷ yñ y ^ñ yr/   c              ƒ  ód   "  € V P                  4       G Rj  x€L
 pRRV 2RRR\        4       /#  L5i)z)JSON REST headers with a fresh bot token.Nr#  r$  zContent-Typezapplication/jsonr%  )r  rP   r'  s   & r-   rç  ÚQQAdapter._auth_headers  s;   é € à×(Ñ(Ó*×*ˆØ 6¨%¨Ð!1°>ÐCUÐWcÔeuÓewÐxÐxñ +ùs   ‚0–.—0c               ó8   € V ^8„  d   QhRRRRRRRRRRR	R
RRRR/# )r_   Útarget_typer'   Ú	target_idÚ	file_typer%   r)  r¼  Ú	file_dataÚsrv_send_msgra   Ú	file_namer`   r  rb   )rc   s   "r-   rd   rs     sN   € ÷ 9ñ 9Øð9Ø+.ð9Ø;>ð9ØERð9à ð9à7;ð9àP]ð9ð 
ñ9r/   c              ƒ  	ó&  a"  € V P                  WR 4      pRVRV/p	V'       d   WIR&   MV'       d   WYR&   V\        8X  d   V'       d   WyR&   \        ^4       F$  p
 V P                  RW‰\        R7      G Rj  x€L
 u # 	  R#  L
  \
         d�   oT
^8X  gA   \        ;QJ d    T3R	 lR 4       F  '       g   K   R
M	  RM! T3R	 lR 4       4      '       d   h \        P                  ! RT
^,           ,          4      G Rj  x€L 
   Ro>K²  Ro>ii ; i5i)ri  r‰  r‹  r)  rŠ  rŒ  ÚPOSTr?  Nc              3  ó>   <"  € T F  q\        S4      9   x € K  	  R # 5irf   )r'   )r5  Úkwrï   s   & €r-   r7  Ú*QQAdapter._upload_media.<locals>.<genexpr>,  s   øé € Ð&pÑ@o¸"¬S°«X¦~Ó@oùs   ƒTFg      ø?)Ú400Ú401ÚInvalidr  ÚTimeout)	Ú
_rest_pathrN   Úranger�  r=   r‚   ÚanyrÆ   rZ  )r+   r‡  rˆ  r‰  r)  rŠ  r‹  rŒ  r¯  r|  Úattemptrï   s   &&&&&&&&   @r-   Ú_upload_mediaÚQQAdapter._upload_media  sÕ   øé € ð �‰˜{°wÓ?ˆØ +¨Y¸ÈÐUˆßØ�ŠKßØ )�ÑØœÔ'¯IØ )�ÑÜ˜Q–xˆGð9Ø!×.Ñ.¨v°tÔK^Ð.Ó_×_Ò_ó  á_øÜô 9Ø˜a”<§3£3Ô&pÑ@oÓ&p§3§3¢3Ô&pÑ@oÓ&p×#pÒ#pØÜ—m’m C¨7°Q­;Õ$7Ó8×8×8ûð9üsj   ƒ-D±DÁDÁBÁ6BÁ7BÁ:DÂBÂDÂD	Â D	Â7D	Ã(D	Ã=D Ã>D	ÄDÄ	DÄDg      .@g      à?c               ó   € V ^8„  d   QhRR/# r^   rb   )rc   s   "r-   rd   rs   3  s   € ÷ ñ ¨dñ r/   c              ƒ  óÄ  "  € \         P                  RV P                  V P                  4       RpWP                  8  dr   \        P
                  ! V P                  4      G Rj  x€L
  WP                  ,          pV P                  '       g   K^  \         P                  RV P                  V4       R# \         P                  RV P                  V P                  4       R#  Lz5i)u�   Poll is_connected for up to _RECONNECT_WAIT_SECONDS â€” covers the race where
send() lands between a disconnect and _listen_loop's reconnect.u=   [%s] Not connected â€” waiting for reconnection (up to %.0fs)r«   Nz[%s] Reconnected after %.1fsTz$[%s] Still not connected after %.0fsF)	rÝ   rå   ry   Ú_RECONNECT_WAIT_SECONDSrÆ   rZ  Ú_RECONNECT_POLL_INTERVALr˜   rÞ   )r+   Úwaiteds   & r-   Ú_wait_for_reconnectionÚ QQAdapter._wait_for_reconnection3  s¥   é € ô 	�‰ØKÈTÏ]É]Ð\`×\xÑ\xô	
ð ˆØ×3Ñ3Ô3Ü—-’- × =Ñ =Ó>×>Ð>Ø×3Ñ3Õ3ˆFØ× × Ò Ü—‘Ð:¸D¿M¹MÈ6ÔRÙÜ�‰Ð=¸t¿}¹}Èd×NjÑNjÔkÙñ ?ùs   ‚A!C Á#CÁ$%C ÂAC c               ó   € V ^8„  d   QhRR/# ©r_   r`   r   rb   )rc   s   "r-   rd   rs   D  s   € ÷ Pñ P 
ñ Pr/   c                	ó   € \        R RRR7      # )FzNot connectedT©Úsuccessrè   r×   )r   r�   s   &r-   Ú_NOT_CONNECTEDÚQQAdapter._NOT_CONNECTEDC  s   € ä %¨È$ÔOÐOr/   c               ó   € V ^8„  d   QhRR/# r^   rb   )rc   s   "r-   rd   rs   G  s   € ÷ Hñ H¨ñ Hr/   c              ƒ  óf   "  € V P                   ;'       g    V P                  4       G Rj  x€L
 #  L5i)zGTrue when connected now or after waiting for the listener to reconnect.N)r˜   r¡  r�   s   &r-   Ú_ensure_connectedÚQQAdapter._ensure_connectedG  s(   é € à× Ñ ×GÐG¨$×*EÑ*EÓ*G×$GÐGÑ$Gùs   ‚(1ª/«1c          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r_   rÄ  r'   rÌ  Úreply_tor¼  Úmetadatar°  r`   r   rb   )rc   s   "r-   rd   rs   K  s4   € ÷ ñ ØðØ%(ðØ4AðØTlðà	ñr/   c              ƒ  ó¦  "  € ?V P                  4       G Rj  x€L
 '       g   V P                  # V'       d   VP                  4       '       g   \        RR7      # V P	                  V P                  V4      V P                  4      p\        RRR7      pV F5  pV P                  WV4      G Rj  x€L
 pVP                  '       g   Vu # RpK7  	  V#  Lµ L$5i)zSSend text/markdown: format, split via truncate_message(), retry transient failures.NT)r§  Fz	No chunks©r§  rè   )	r¬  r¨  r°   r   Útruncate_messageÚformat_messagerD   Ú_send_chunkr§  )r+   rÄ  rÌ  r¯  r°  ÚchunksÚlast_resultÚchunks   &&&&&   r-   ÚsendÚQQAdapter.sendK  s¸   é € ð Ø×+Ñ+Ó-×-Ö-Ø×&Ñ&Ð&ß˜gŸm™mŸošoÜ dÔ+Ð+à×&Ñ& t×':Ñ':¸7Ó'CÀT×E\ÑE\Ó]ˆÜ ¨°kÔBˆÛˆEØ $× 0Ñ 0°ÀÓ J×JˆKØ×&×&Ð&Ø"Ò"ØŠHñ	 ð
 Ðñ .ñ Kùs8   ‚C—C˜	C¢C¶CÁACÂ*CÂ+CÃCÃCc               ó(   € V ^8„  d   QhRRRRRRRR/# )r_   rÄ  r'   rÌ  r¯  r¼  r`   r   rb   )rc   s   "r-   rd   rs   `  s/   € ÷ Oñ O¨ð O°sð OÀmð OÐ_iñ Or/   c           	   ƒ  	ó  a	a
"  € R pV P                  V P                  V4      4      pVf   \        RRV 2R7      # \        ^4       F  p V! WV4      G R j  x€L
 u # 	  V'       d)   \        V4      ;'       g    \        V4      P                  MRo	\        P                  R	V P                  S	4       \
        ;QJ d)    V	3R
 lV P                   4       F  '       g   K   RM	  RM! V	3R
 lV P                   4       4      '       * p\        RS	VR7      #  L¼  \         dà   o
S
p\
        ;QJ d0    T
3R lT P                  R,            4       F  '       g   K   RM%	  RM!! T
3R lT P                  R,            4       4      '       d	    R o
>
 EK-  T^8  da   R^T,          ,          p\        P                  RT P                  T^,           TS
4       \        P                  ! T4      G R j  x€L 
   R o
>
EK­   R o
>
EK´  R o
>
ii ; i5i)NFzUnknown chat type for r²  c              3  óZ   <"  € T F   q\        S4      P                  4       9   x € K"  	  R # 5irf   )r'   r³   )r5  r¡  rï   s   & €r-   r7  Ú(QQAdapter._send_chunk.<locals>.<genexpr>j  s!   øé € ÐeÑ6d°œC ›HŸN™NÓ,Ö,Ó6dùs   ƒ(+Tg      ð?z$[%s] send retry %d/3 after %.1fs: %szUnknown errorz[%s] Send failed: %sc              3  óH   <"  € T F  qSP                  4       9   x € K  	  R # 5irf   )r³   )r5  r¡  Ú	error_msgs   & €r-   r7  r¾  s  s   øé € ÐXÑ<W°q §¡Ó!2Ö2Ó<Wùs   ƒ"r¦  )zbad request)Ú_text_senderÚ_guess_chat_typer   r—  rç   r˜  Ú_PERMANENT_SEND_ERRORSrÝ   rÞ   ry   rÆ   rZ  r'   rj  r1   rè   )r+   rÄ  rÌ  r¯  Úlast_excÚsenderr™  re  r×   rÀ  rï   s   &&&&     @@r-   rµ  ÚQQAdapter._send_chunk`  s‚  ùé € Ø(,ˆØ×"Ñ" 4×#8Ñ#8¸Ó#AÓBˆØŠ>Ü eÐ5KÈGÈ9Ð3UÔVÐVÜ˜Q–xˆGð	/Ù# G°hÓ?×?Ò?ñ  ÷ CK”S˜“]×=Ð=¤d¨8£n×&=Ñ&=øÐP_ˆ	Ü�‰Ð+¨T¯]©]¸IÔFß›ÔX¸D×<WÒ<WÓXŸŸšÔX¸D×<WÒ<WÓXÓXÔXˆ	Ü %¨yÀIÔNÐNñ @øÜô /Ø�ß“3Ôe°d×6QÑ6QÐTdÖ6dÓe—3—3’3Ôe°d×6QÑ6QÐTdÖ6dÓe×eÒeßØ˜Q”;Ø 1¨¥<Õ0�EÜ—N‘NÐ#IÈ4Ï=É=ÐZaÐdeÕZeÐglÐnqÔrÜ!Ÿ-š-¨Ó.×.×.Ð.ö ûð	/üsz   „AHÁ
DÁDÁDÁHÁ'HÁ9AHÂ=HÃ5HÄDÄG?Ä 2G:Å.G:ÆHÆAG:Ç&G)Ç'G:Ç,HÇ:G?Ç?Hc               ó(   € V ^8„  d   QhRRRRRRRR/# )r_   rô  r'   rˆ  Úendpointr`   rb   )rc   s   "r-   rd   rs   w  s(   € ÷ 4ñ 4˜cð 4¨cð 4¸Sð 4ÀSñ 4r/   c                ó.   € V R8X  d   RMRpRV RV RV 2# )zA``/v2/{users|groups}/{id}/{endpoint}`` for a c2c user or a group.rÿ  ÚusersÚgroupsz/v2/rY  rb   )rô  rˆ  rÈ  Úkinds   &&& r-   r–  ÚQQAdapter._rest_pathv  s+   € ð $ uÔ,‰w°(ˆØ�d�V˜1˜Y˜K q¨¨
Ð3Ð3r/   c               ó$   € V ^8„  d   QhRRRRRR/# )r_   rô  r'   rˆ  r`   rb   )rc   s   "r-   rd   rs   }  s&   € ÷ @ñ @ sð @°sð @¸sñ @r/   c                	ó&   € V P                  WR 4      # )Úmessages)r–  )r  rô  rˆ  s   &&&r-   Ú_messages_pathÚQQAdapter._messages_path|  s   € à�~‰~˜i°JÓ?Ð?r/   c               ó$   € V ^8„  d   QhRRRRRR/# )r_   r¯  r'   r|  r  r`   r   rb   )rc   s   "r-   rd   rs   €  s&   € ÷ rñ r¨ð r°>ð rÀjñ rr/   c           
   ƒ  óØ   "  € V P                  RW4      G Rj  x€L
 p\        R\        VP                  R\        P
                  ! 4       P                  R,          4      4      VR7      #  LO5i)zEPOST a message body and wrap the response as a successful SendResult.rŽ  NTrÊ  :Né   N)r§  rÂ  Úraw_response)r�  r   r'   r®   r¸  r¹  rº  )r+   r¯  r|  r  s   &&& r-   Ú_post_messageÚQQAdapter._post_message€  sQ   é € à×&Ñ& v¨tÓ:×:ˆÜ $´3°t·x±xÀÄdÇjÂjÃl×FVÑFVÐWZÕF[Ó7\Ó3]ÐlpÔqÐqñ ;ùs   ‚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ˆ  rÌ  r¯  r¼  ÚkeyboardzOptional[InlineKeyboard]r`   r   rb   )rc   s   "r-   rd   rs   …  sD   € ÷ 
Yñ 
YØð
YØ),ð
YØ7:ð
YØFSð
Yà*ð
Yà6@ñ
Yr/   c              ƒ  óþ   "  € T P                  T;'       g    T4       V P                  W44      pV'       d   WFR&   Ve   VP                  4       VR&   V P                  V P	                  W4      V4      G Rj  x€L
 #  L5i)zFSend text (optionally with an inline keyboard) to a c2c user or group.rµ  NrÚ  )r½  Ú_build_text_bodyÚto_dictr×  rÑ  )r+   rô  rˆ  rÌ  r¯  rÚ  r|  s   &&&&&& r-   Ú_send_text_toÚQQAdapter._send_text_to…  su   é € ð 	×Ñ˜8×0Ð0 yÔ1Ø×$Ñ$ WÓ7ˆßØ%�‰NØÒØ'×/Ñ/Ó1ˆD�ÑØ×'Ñ'¨×(;Ñ(;¸IÓ(QÐSWÓX×XÐXÑXùs   ‚A4A=Á6A;Á7A=c               ó   € V ^8„  d   QhRR/# r¤  rb   )rc   s   "r-   rd   rs   ‘  s   € ÷ Tñ TÐU_ñ Tr/   c              ƒ  	óD   "  € V P                  R WW44      G Rj  x€L
 #  L5i)rÿ  N©rÞ  )r+   ÚopenidrÌ  r¯  rÚ  s   &&&&&r-   Ú_send_c2c_textÚQQAdapter._send_c2c_text‘  s    é € Ø×'Ñ'¨¨vÀÓS×SÐSÑSùó   ‚ ™š c               ó   € V ^8„  d   QhRR/# r¤  rb   )rc   s   "r-   rd   rs   ”  s   € ÷ \ñ \Ð]gñ \r/   c              ƒ  	óD   "  € V P                  R WW44      G Rj  x€L
 #  L5i)r   Nrâ  )r+   r  rÌ  r¯  rÚ  s   &&&&&r-   Ú_send_group_textÚQQAdapter._send_group_text”  s    é € Ø×'Ñ'¨°ÈÓ[×[Ð[Ñ[ùræ  rÿ  rä  r   ré  r  Ú_send_guild_textÚkeyboard_okc               ó    € V ^8„  d   QhRRRR/# )r_   rô  r'   rì  ra   rb   )rc   s   "r-   rd   rs   ™  s   € ÷ 5ñ 5 cð 5¸4ñ 5r/   c               ó„   € V'       d
   VR8X  d   R# V P                   P                  V4      pV'       d   \        W4      # R# )zOBound text sender for *chat_type* (None if unsupported); guild lacks keyboards.r  N)Ú_TEXT_SENDERSr®   rw   )r+   rô  rì  rÎ   s   &&$ r-   rÁ  ÚQQAdapter._text_sender™  s7   € ç˜9¨Ô/ÙØ×!Ñ!×%Ñ% iÓ0ˆß&*Œw�tÓ"Ð4°Ð4r/   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r_   rH  r'   rÌ  r¯  r¼  r`   r   rb   )rc   s   "r-   rd   rs      s/   € ÷ Rñ R°ð R¸sð RÈmð RÐgqñ Rr/   c              ƒ  	ó„   "  € R VRV P                    /pV'       d   W4R&   V P                  RV R2V4      G Rj  x€L
 #  L5i)rÌ  Nrµ  z
/channels/ú	/messages)rD   r×  )r+   rH  rÌ  r¯  r|  s   &&&& r-   rë  ÚQQAdapter._send_guild_text   sI   é € Ø )¨7Ð3L°T×5LÑ5LÐ+MÐNˆßØ%�‰NØ×'Ñ'¨*°Z°LÀ	Ð(JÈDÓQ×QÐQÑQùs   ‚7A ¹>ºA c          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r_   rÄ  r'   rÌ  rÚ  rU   r¯  r¼  r`   r   rb   )rc   s   "r-   rd   rs   ¨  s;   € ÷ Sñ SØðSØ%(ðSØ4BðSØN[ðSà	ñSr/   c              ƒ  ó  "  € V P                  4       G Rj  x€L
 '       g   V P                  # V P                  V4      pV P                  VRR7      pVf   \	        RRV: 2RR7      # V P                  V4      RV P                   p V! WWCR7      G Rj  x€L
 #  L� L  \         d_   p\        P                  RT P                  T4       \	        R\        T4      ;'       g    \        T4      P                  R	7      u Rp?# Rp?ii ; i5i)
u“   Send ONE text message with an inline keyboard (no chunking â€” splitting
would orphan the buttons; keep bodies short). Guild chats are unsupported.NT)rì  Fz-Inline keyboards not supported for chat_type r¦  )rÚ  z"[%s] send_with_keyboard failed: %sr²  )r¬  r¨  rÂ  rÁ  r   r´  rD   rç   rÝ   rè   ry   r'   rj  r1   )	r+   rÄ  rÌ  rÚ  r¯  rô  rÅ  Ú	truncatedrï   s	   &&&&&    r-   Úsend_with_keyboardÚQQAdapter.send_with_keyboard¨  sø   é € ð
 ×+Ñ+Ó-×-Ö-Ø×&Ñ&Ð&Ø×)Ñ)¨'Ó2ˆ	Ø×"Ñ" 9¸$Ð"Ó?ˆØŠ>ÜØÐ'TÐU^ÑTaÐ%bÐnsôuð uà×'Ñ'¨Ó0Ð1J°4×3JÑ3JÐKˆ	ð	SÙ °HÔP×PÐPñ .ñ QøÜô 	SÜ�L‰LÐ=¸t¿}¹}ÈcÔRÜ e´3°s³8×3QÐ3Q¼tÀC»y×?QÑ?QÔRÕRûð	SüsX   ‚D–B—	D¡A$DÂB ÂBÂB ÂDÂB ÂDÂ'AD Ã:DÃ;DÄ DÄDc               ó(   € V ^8„  d   QhRRRRRRRR/# )	r_   rÄ  r'   ÚreqrT   r¯  r¼  r`   r   rb   )rc   s   "r-   rd   rs   »  s2   € ÷ mñ mØðmØ!0ðmØ<IðmØU_ñmr/   c              ƒ  ó    "  € ^RI Hp \        VP                  \	        VRR4      R7      pV P                  W! V4      WSR7      G Rj  x€L
 #  L5i)z’Send a 3-button approval request (allow-once / allow-always / deny);
clicks come back as INTERACTION_CREATE decoded by parse_approval_button_data.)Úbuild_approval_textÚallow_permanentT)rþ  ©r¯  N)Ú	keyboardsrý  rW   rï  rw   rø  )r+   rÄ  rû  r¯  rý  rÚ  s   &&&&  r-   Úsend_approval_requestÚQQAdapter.send_approval_request»  sK   é € õ 	3Ü*¨3¯?©?ÌGÐTWÐYjÐlpÓLqÔrˆØ×,Ñ,¨WÐ6IÈ#Ó6NÐPXÐ,Ól×lÐlÑlùs   ‚AAÁAÁAi,  c               ó    € V ^8„  d   QhRRRR/# )r_   Úpromptr   r`   r   rb   )rc   s   "r-   rd   rs   È  s   € ÷ Qñ QÐ7Ið QÈjñ Qr/   c           	   ƒ  ód  "  € VP                   pVP                  '       d
   VR,          p\        VP                  RVVP                  V P
                  RVP                  9   R7      pV P                  VP                  W0P                  P                  VP                  4      R7      G Rj  x€L
 #  L5i)a  Keyboard-card approval (called while the agent blocks on approval); clicks resolve via
_default_interaction_dispatch. QQ's 3-button keyboard has no session tier and no thread /
DM targeting, so only the ``always`` choice and the raw command/reason are used.z3 Owner override applies to this one operation only.zExecute this command?rì  )rï  ÚtitleÚdescriptionÚcommand_previewÚtimeout_secrþ  rÿ  N)r  Úsmart_deniedrT   rï  ÚcommandÚ_APPROVAL_TIMEOUT_SECONDSrj  r  rÄ  rÂ   r®   )r+   r  r  rû  s   &&  r-   Ú_send_exec_approval_promptÚ$QQAdapter._send_exec_approval_promptÈ  s£   é € ð ×(Ñ(ˆØ××ÐØÐPÕPˆKÜØ×*Ñ*Ð2IÐWbØ"ŸN™N¸×8VÑ8VØ$¨¯©Ñ6ô8ˆð
 ×/Ñ/Ø�N‰N˜C×*;Ñ*;×*?Ñ*?ÀÇÁÓ*Oð 0ó Q÷ Qð 	Qñ Qùs   ‚B'B0Â)B.Â*B0c               ó0   € V ^8„  d   QhRRRRRRRRRRRR	/# )
r_   rÄ  r'   r  Údefaultrï  r°  r°  r`   r   rb   )rc   s   "r-   rd   rs   ×  s<   € ÷ 

ñ 

Øð

Ø$'ð

Ø25ð

ØILð

à*ð

à6@ñ

r/   c              ƒ  óº   "  € ??V'       d   RV R2MRpRV V 2pV P                  W\        4       V P                  P                  V4      R7      G Rj  x€L
 #  L5i)z“Yes/No update-confirmation prompt; button clicks (``update_prompt:y|n``)
are written to ``~/.hermes/.update_response`` by the interaction callback.z (default: r$   r#   u!   â˜¤ **Update Needs Your Input**

rÿ  N)rø  rX   rÂ   r®   )r+   rÄ  r  r  rï  r°  Údefault_hintrÌ  s   &&&&&&  r-   Úsend_update_promptÚQQAdapter.send_update_prompt×  sm   é € ð
 ˜ß3:˜ W I¨QÑ/ÀˆØ7¸°xÀ¸~ÐNˆØ×,Ñ,ØÔ:Ó<Àt×GXÑGX×G\ÑG\Ð]dÓGeð -ó 
÷ 
ð 	
ñ 
ùs   ‚AAÁAÁAc               ó$   € V ^8„  d   QhRRRRRR/# )r_   rÌ  r'   r¯  r¼  r`   r  rb   )rc   s   "r-   rd   rs   ã  s"   € ÷ ñ ¨ð °}ð ÐP^ñ r/   c                	óÐ   € T P                  T;'       g    R 4      pVRV P                   pV P                  '       d   RRV/R\        RV/# RVR\        RV/pV'       d   RV/VR&   V# )r  NÚmarkdownrÌ  Úmsg_typeÚmsg_seqrÂ  Úmessage_reference)r½  rD   r²   rH   rG   )r+   rÌ  r¯  r  ré  r|  s   &&&   r-   rÜ  ÚQQAdapter._build_text_bodyã  s   € Ø×$Ñ$ X×%:Ð%:°Ó;ˆØÐ0˜×0Ñ0Ð1ˆØ×!×!Ð!Ø ¨DÐ 1°:Ô?PÐR[Ð]dÐeÐeØ )¨4°¼]ÈIÐW^Ð_ˆßØ)5°xÐ(@ˆDÐ$Ñ%Øˆr/   c               ó0   € V ^8„  d   QhRRRRRRRRRRR	R
/# )r_   rÄ  r'   Ú	image_urlÚcaptionr¼  r¯  r°  r°  r`   r   rb   )rc   s   "r-   rd   rs   ï  sD   € ÷ 
Uñ 
UØð
UØ'*ð
UØ5Bð
UØUbð
Uà*ð
Uà6@ñ
Ur/   c              ƒ  óX  "  € ?V P                  W\        RW44      G Rj  x€L
 pVP                  '       g   V P                  V4      '       g   V# \        P                  RV P                  VP                  4       V'       d   V RV 2MTpV P                  WVR7      G Rj  x€L
 #  L† L5i)zLSend an image natively via QQ Bot API upload; URL sources fall back to text.r”  Nz0[%s] Image send failed, falling back to text: %src  )rÄ  rÌ  r¯  )	Ú_send_mediarK   r§  Ú_is_urlrÝ   rÞ   ry   rè   r¹  )r+   rÄ  r  r  r¯  r°  r  rÆ  s   &&&&&&  r-   Ú
send_imageÚQQAdapter.send_imageï  s“   é € ð Ø×'Ñ'¨Ô<LÈgÐW^Ói×iˆØ�>�>ˆ> §¡¨i×!8Ò!8ØˆMÜ�‰ÐIÈ4Ï=É=ÐZ`×ZfÑZfÔgß07�g�Y˜b  Ñ,¸YˆØ—Y‘Y wÈ8�YÓT×TÐTñ jñ
 Uùs2   ‚B*ŸB& B*¶B*Á4B*ÂB*Â!B(Â"B*Â(B*c               ó   € V ^8„  d   QhRR/# r¤  rb   )rc   s   "r-   rd   rs   û  s   € ÷ iñ iÐcmñ ir/   c              ‹  	óN   "  € V P                  W\        R W44      G Rj  x€L
 #  L5i)r”  N)r   rK   )r+   rÄ  Ú
image_pathr  r¯  Úkwargss   &&&&&,r-   Úsend_image_fileÚQQAdapter.send_image_fileû  ó$   é € Ø×%Ñ% gÔ;KÈWÐV]Óh×hÐhÑhùó   ‚%ž#Ÿ%c               ó   € V ^8„  d   QhRR/# r¤  rb   )rc   s   "r-   rd   rs   þ  ó   € ÷ iñ iÐ^hñ ir/   c              ‹  	óN   "  € V P                  W\        R W44      G Rj  x€L
 #  L5i)r‘  N)r   rM   )r+   rÄ  Ú
audio_pathr  r¯  r'  s   &&&&&,r-   Ú
send_voiceÚQQAdapter.send_voiceþ  r*  r+  c               ó   € V ^8„  d   QhRR/# r¤  rb   )rc   s   "r-   rd   rs     r-  r/   c              ‹  	óN   "  € V P                  W\        R W44      G Rj  x€L
 #  L5i)r“  N)r   rL   )r+   rÄ  Ú
video_pathr  r¯  r'  s   &&&&&,r-   Ú
send_videoÚQQAdapter.send_video  r*  r+  c               ó   € V ^8„  d   QhRR/# r¤  rb   )rc   s   "r-   rd   rs     s   € ÷ añ aà	ñar/   c           
   ‹  	óR   "  € V P                  W\        R W5VR7      G Rj  x€L
 #  L5i)r¨  )rŒ  N)r   rN   )r+   rÄ  Ú	file_pathr  rŒ  r¯  r'  s   &&&&&&,r-   Úsend_documentÚQQAdapter.send_document  s9   é € ð ×%Ñ%Ø¤°¸ÐV_ð &ó a÷ að 	añ aùs   ‚' %¡'c               ó8   € V ^8„  d   QhRRRRRRRRRRR	RR
RRR/# )r_   rÄ  r'   Úmedia_sourcer‰  r%   rÌ  r  r¼  r¯  rŒ  r`   r   rb   )rc   s   "r-   rd   rs   
  sV   € ÷ .Sñ .SØð.SØ*-ð.SØ:=ð.SØEHð.SØS`ð.Sàð.Sà3@ð.SàLVñ.Sr/   c              ƒ  óP  "  € V P                  4       G Rj  x€L
 '       g   V P                  # V P                  V4      pVR8X  d   \        RRR7      #  V P	                  V4      '       dh   T;'       g3    \        \        V4      P                  4      P                  ;'       g    Rp	T P                  Y�Y2RV\        8X  d   T	MRR7      G Rj  x€L
 p
MV P                  W�W#V4      G Rj  x€L
 p
V
P                  R4      ;'       g,    V
P                  R	/ 4      ;'       g    / P                  R4      pV'       g   \        RR
V
 2R7      # R\        RRV/RV P                  V4      /pV'       d   VRV P                   VR&   V'       d   WlR&   V P!                  V P#                  W�4      V4      G Rj  x€L
 #  ELž Lë LÑ L  \$         dk   p\&        P)                  RT P*                  TP,                  TP.                  4       \        RRRTP,                  : RTP.                   R2R7      u Rp?# Rp?i\0         d‚   p\&        P)                  RT P*                  TP,                  TP.                  TP2                  4       \        RRTP,                  : RTP.                   RTP2                   R2R7      u Rp?# Rp?i\4         d_   p\&        P7                  RT P*                  T4       \        R\9        T4      ;'       g    \;        T4      P<                  R7      u Rp?# Rp?ii ; i5i)uâ   Upload media and send as a native message. HTTP(S) URLs â†’ single ``POST
.../files`` with ``url=`` (QQ fetches it). Local files â†’ chunked upload
(prepare / PUT parts / complete), up to the platform's ~100 MB per-file limit.Nr  Fz,Guild media send not supported via this pathr²  Úmedia)r)  r‹  rŒ  Ú	file_infor  zUpload returned no file_info: r  r  rÌ  rµ  z,[%s] Daily upload limit exceeded for %s (%s)z#QQ daily upload limit exceeded for rª  z). Retry tomorrow.)r§  r×   rè   z/[%s] File too large: %s (%s, platform limit %s)z() exceeds the QQ per-file upload limit (z).z[%s] Media send failed: %s)r¬  r¨  rÂ  r   r!  r   r   r¯  rÎ   rš  rN   Ú_upload_local_filer®   rI   r½  rD   r×  rÑ  rR   rÝ   rÞ   ry   rŒ  Úfile_size_humanrS   Úlimit_humanrç   rè   r'   rj  r1   )r+   rÄ  r=  r‰  rÌ  r  r¯  rŒ  rô  Úresolved_nameÚuploadr@  r|  rï   s   &&&&&&&&      r-   r   ÚQQAdapter._send_media
  sÐ  é € ð ×+Ñ+Ó-×-Ö-Ø×&Ñ&Ð&Ø×)Ñ)¨'Ó2ˆ	Ø˜ÔÜ eÐ3aÔbÐbð"	SØ�|‰|˜L×)Ò)Ø )× ^Ð ^¬T´(¸<Ó2H×2MÑ2MÓ-N×-SÑ-S× ^Ð ^ÐW^�Ø#×1Ñ1Ø¨	ÐRWØ/8¼OÔ/K™mÐQUð  2ó  W÷ W‘ð  $×6Ñ6°yÈ<ÐdmÓn×n�àŸ
™
 ;Ó/×bÐb°F·J±J¸vÀrÓ4J×4PÐ4PÈb×3UÑ3UÐVaÓ3bˆIßÜ!¨%Ð9WÐX^ÐW_Ð7`ÔaÐaàœN¨G°kÀ9Ð5MÈyÐZ^×ZlÑZlÐmtÓZuð$wˆDçØ")Ð*C¨D×,CÑ,CÐ"D��Y‘ßØ!)�X‘Ø×+Ñ+¨D×,?Ñ,?À	Ó,SÐUYÓZ×ZÐZò1 .ñWñ oñ [øÜ,ô 	xä�N‰NÐIÈ4Ï=É=ÐZ]×ZgÑZgÐil×i|Ñi|Ô}ÜØ¨Ø;¸C¿M¹MÑ;LÈBÈs×ObÑObÐNcÐcuÐvôxõ xûô 'ô 	~Ü�N‰NØAØ—‘˜sŸ}™}¨c×.AÑ.AÀ3Ç?Á?ôTô Ø¨ØŸ™Ñ)¨¨C×,?Ñ,?Ð+@Ð@hÐil×ixÑixÐhyÐy{Ð|ô~õ ~ûô ô 	SÜ�L‰LÐ5°t·}±}ÀcÔJÜ e´3°s³8×3QÐ3Q¼tÀC»y×?QÑ?QÔRÕRûð	Süsõ   ‚L&–F4—	L&¡1L&ÁF= Á*F= Á3/F= Â#(F= ÃF7ÃF= Ã'F9Ã(F= ÄF= ÄF= Ä8F= ÅL&Å$F= Å-F= Æ(F= Æ/F;Æ0F= Æ3L&Æ7F= Æ9F= Æ;F= Æ=L#ÇAH-È'L#È(L&È-L#È:L#È;A6J7Ê1L#Ê2L&Ê7L#ËL#ËALÌL#ÌL&ÌL#Ì#L&c               ó0   € V ^8„  d   QhRRRRRRRRRRR	R
/# )r_   rô  r'   rÄ  r=  r‰  r%   rŒ  r¼  r`   r  rb   )rc   s   "r-   rd   rs   :  s<   € ÷ 4ñ 4Øð4Ø'*ð4Ø:=ð4ØJMð4ØZgð4à	ñ4r/   c              ƒ  óŒ  "  € V P                  4       p\        V4      P                  4       pVP                  4       '       g+   \        P                  ! 4       V,          P                  4       pVP                  4       '       d   VP                  4       '       gE   VP                  R4      '       g   \        V4      ^8  d   \        RV: 24      h\        RV 24      h\        V P                  VP                  V P                  R7      pTP!                  Y\#        V4      TT;'       g    VP$                  R7      G Rj  x€L
 #  L5i)a  Chunked-upload a local file; returns the complete response whose ``file_info`` goes
into the RichMedia body. Raises UploadDailyLimitExceededError / UploadFileTooLargeError
from the uploader, ValueError for placeholder paths like ``<path>``, FileNotFoundError.Ú<z1Invalid media source (looks like a placeholder): zMedia file not found: )Úapi_requestÚhttp_putÚlog_tag)rô  rˆ  r9  r‰  rŒ  N)rå  r   Ú
expanduserÚis_absoluteÚcwdÚresolverß  Úis_filer«  rd  r}  rK  rQ   r�  ræ  ry   rE  r'   rÎ   )	r+   rô  rÄ  r=  r‰  rŒ  r€  Ú
local_pathÚuploaders	   &&&&&&   r-   rA  ÚQQAdapter._upload_local_file:  s  é € ð ×*Ñ*Ó,ˆÜ˜,Ó'×2Ñ2Ó4ˆ
Ø×%Ñ%×'Ò'ÜŸ(š(›* zÕ1×:Ñ:Ó<ˆJØ× Ñ ×"Ò"¨*×*<Ñ*<×*>Ò*>Ø×&Ñ& s×+Ò+¬s°<Ó/@À1Ô/DÜ Ð#TÐUaÑTdÐ!eÓfÐfÜ#Ð&<¸Z¸LÐ$IÓJÐJä"¨t×/@Ñ/@È6Ï:É:Ð_c×_lÑ_lÔmˆØ—_‘_Ø¼cÀ*»oÐYbØ×2Ð2 :§?¡?ð %ó 4÷ 4ð 	4ñ 4ùs%   ‚A?EÂEÂEÂ/BEÄ=EÄ>Ec               ó    € V ^8„  d   QhRRRR/# )r_   rÄ  r'   r`   r|   rb   )rc   s   "r-   rd   rs   P  s   € ÷ Lñ L¨ð LÀñ Lr/   c           
   ƒ  ó^  "  € V P                   P                  V4      p\        P                  ! 4       pV P                  '       dP   V P	                  V4      R8w  g:   V'       d2   W@P
                  P                  VR4      ,
          V P                  8  d   R#  R\        RVRR^RV P                  /R	V P                  V4      /pV P                  R
RV R2V4      G Rj  x€L
  W@P
                  V&   R#  L  \         d-   p\        P                  RT P                  T4        Rp?R# Rp?ii ; i5i)zzC2C-only input notify, debounced to ~50s (API shows a 60s indicator);
needs the last inbound msg_id from ``_last_msg_id``.rÿ  r«   Nr  rµ  Úinput_notifyÚ
input_typeÚinput_secondr  rŽ  z
/v2/users/ró  z[%s] send_typing failed: %s)rÂ   r®   r  r˜   rÂ  rÃ   Ú_TYPING_DEBOUNCE_SECONDSrJ   Ú_TYPING_INPUT_SECONDSr½  r�  rç   rÝ   r|  ry   )r+   rÄ  r°  rµ  Únowr|  rï   s   &&&    r-   Úsend_typingÚQQAdapter.send_typingP  s  é € ð ×"Ñ"×&Ñ& wÓ/ˆÜ�iŠi‹kˆà×!×!Ð! T×%:Ñ%:¸7Ó%CÀuÔ%L×TZØ×)Ñ)×-Ñ-¨g°sÓ;Õ;¸d×>[Ñ>[Ô[áð		LàÔ1Ø˜&Ø ¨q°.À$×B\ÑB\Ð ]Ø˜4×-Ñ-¨gÓ6ð	8ˆDð
 ×#Ñ# F¨j¸¸	ÀÐ,KÈTÓR×RÐRØ,/× Ñ  Ó)ñ Søäô 	LÜ�L‰LÐ6¸¿¹Às×KÒKûð	LüsI   ‚A D-Á#3D-ÂAC3 ÃC1ÃC3 Ã/D-Ã1C3 Ã3D*Ã>!D%ÄD-Ä%D*Ä*D-c               ó    € V ^8„  d   QhRRRR/# ©r_   rÌ  r'   r`   rb   )rc   s   "r-   rd   rs   g  s   € ÷ Nñ N cð N¨cñ Nr/   c                ó@   € V P                   '       d   V# \        V4      # )zLPass markdown through when supported, else strip it (as BlueBubbles/SMS do).)r²   r   )r+   rÌ  s   &&r-   r´  ÚQQAdapter.format_messageg  s   € à×0×0Ð0ˆwÐM´nÀWÓ6MÐMr/   c               ó    € V ^8„  d   QhRRRR/# )r_   rÄ  r'   r`   r  rb   )rc   s   "r-   rd   rs   k  s   € ÷ _ñ _¨3ð _°>ñ _r/   c              ƒ  	óL   "  € V P                  V4      pR TRVR9   d   R/# R/# 5i)rÎ   rj  r   rþ  >   r   r  )rÂ  )r+   rÄ  rô  s   && r-   Úget_chat_infoÚQQAdapter.get_chat_infok  s5   é € Ø×)Ñ)¨'Ó2ˆ	Ø˜ °IÐASÔ4S¨Ð^Ð^ÐY]Ð^Ð^ùs   ‚"$c               ó    € V ^8„  d   QhRRRR/# )r_   rÃ  r'   r`   ra   rb   )rc   s   "r-   rd   rs   p  s   € ÷ Añ A˜ð A ñ Ar/   c                	óD   € \        \        V 4      4      P                  R9   # )Úhttp>   ri  Úhttps)r   r'   Úscheme)rÃ  s   &r-   r!  ÚQQAdapter._is_urlo  s   € äœ˜F›Ó$×+Ñ+Ð/@Ñ@Ð@r/   c               ó    € V ^8„  d   QhRRRR/# )r_   rÄ  r'   r`   rb   )rc   s   "r-   rd   rs   s  s   € ÷ 7ñ 7¨ð 7°ñ 7r/   c                ó:   € V P                   P                  VR4      # )zDDetermine chat type from stored inbound metadata, fallback to 'c2c'.rÿ  )rÀ   r®   )r+   rÄ  s   &&r-   rÂ  ÚQQAdapter._guess_chat_types  s   € à×"Ñ"×&Ñ& w°Ó6Ð6r/   c               ó    € V ^8„  d   QhRRRR/# r`  rb   )rc   s   "r-   rd   rs   x  s   € ÷ 8ñ 8 3ð 8¨3ñ 8r/   c                	óN   € \         P                  ! R RV P                  4       4      # )z^@\S+\s*r#   )ÚreÚsubr°   )rÌ  s   &r-   rB  ÚQQAdapter._strip_at_mentionw  s   € ä�vŠv�k 2 w§}¡}£Ó7Ð7r/   c               ó$   € V ^8„  d   QhRRRRRR/# )r_   Úentriesz	list[str]Útargetr'   r`   ra   rb   )rc   s   "r-   rd   rs   {  s&   € ÷ Xñ X ið X¸ð XÀñ Xr/   c                	óÆ   a€ \        V4      P                  4       P                  4       o\        ;QJ d    V3R  lV 4       F  '       g   K   R# 	  R# ! V3R  lV 4       4      # )c              3  ó|   <"  € T F1  p\        V4      P                  4       P                  4       R S39   x € K3  	  R# 5i)Ú*N)r'   r°   r³   )r5  ry  Únormalized_targets   & €r-   r7  Ú+QQAdapter._entry_matches.<locals>.<genexpr>}  s/   øé € ÐWÉwÈ!”3�q“6—<‘<“>×'Ñ'Ó)¨cÐ3DÐ-EÖEËwùs   ƒ9<TF)r'   r°   r³   r˜  )r+   rv  rw  r{  s   &&&@r-   Ú_entry_matchesÚQQAdapter._entry_matches{  sH   ø€ Ü ›K×-Ñ-Ó/×5Ñ5Ó7Ðß‹sÔWÉwÓW�sŒsÐWŠsÐWˆsÔWÉwÓWÓWÐWr/   c               ó    € V ^8„  d   QhRRRR/# )r_   r¯  r'   r`   r   rb   )rc   s   "r-   rd   rs     s   € ÷ $ñ $ sð $¨xñ $r/   c                óà  € V'       dI   \         P                  ! \        \        4      ;_uu_ 4        \        P
                  ! V4      uuRRR4       # \        P                  ! \        R7      #   + '       g   i     M; i\         P                  ! \        \        4      ;_uu_ 4        \        P                  ! \        T4      R,          \        R7      uuRRR4       #   + '       g   i     Lœ; i)uJ   Parse a QQ timestamp â€” ISO 8601 string (current) or integer ms (legacy).Niè  )Útz)
ry  rz  r}  r|  r   ÚfromisoformatÚfromtimestampr%   r   r\  )r+   r¯  s   &&r-   rq  ÚQQAdapter._parse_qq_timestamp  s‚   € çÜ×$Ò$¤Z´×;Õ;Ü×-Ò-¨cÓ2÷ <Ò;ô �|Š|œsÔ#Ð#÷	 <×;úä×$Ò$¤Z´×;Õ;Ü×-Ò-¬c°#«h¸­oÄ#ÔF÷ <×;×;Ò;ús   °A,Á,A<	Â&,CÃC-	)rÄ   r¶   ru   rÀ   r±   rÁ   r´   r¸   r·   r½   r¼   rº   rÊ   rÂ   r¿   r»   r²   r~   r•   r¹   r¾   rÅ   rÈ   rÃ   r–   )r�  r0   )	)s   #!SILKr  )s   !r  )s   RIFFrÜ  )s   fLaCú.flac)s   ÿûú.mp3)s   ÿór†  )s   ÿòr†  )s   0&²uú.ogg)s   OggSr‡  )NNFN)NN)ÚinvalidÚ	forbiddenz	not foundrf   )r#   r#   N)NNN)ƒr1   r2   r3   r4   r5   ÚSUPPORTS_MESSAGE_EDITINGrD   ÚALLOW_ALL_ENV_PREFIXr[  rZ  rY  Úsetr—  r[  Úpropertyry   r…   r‘   r˜   r*   rÎ   rð   rõ   rú   ré   r	  r  r  r*  rà   r.  râ   rO  rW  rã   r‚  rŒ  r“  Ústaticmethodr˜  rœ  rn  rm  r½  rÅ  r©  rÔ  rª  rØ  r  rù  r  r  rÉ   r  r;  rD  rM  rQ  r¨  r]  r7  rn  ro  rp  rl  r   r®  r¬  rÊ  r­  rÝ  rá  rý  Úclassmethodr  rÞ  r  r
  r  r  r  r  rd  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  r  rÜ  r"  r(  r0  r5  r:  r   rA  r]  r´  re  r!  rÂ  rB  r}  rq  r6   r7   r8   s   @r-   rn   rn   d   se  ø† ÙTð  %ÐØ+ÐØÐØÐØ!Ðð 	Ð Ð&7¸¸ØÐ! 4Ð)>ÀÐFVØÐ% tÐ-CÀTÈ8ðUÐð %)¨$ <±#±e¸DÀ$Ó6GÓ2HÕ#HÐ àô8ó ð8õ
(õ`ð ôHó ðH÷!0ð !0ðJ ôó ðð
$°E÷ $õL8õõ+õOõVõ&õ&	ð)¸÷ )õ	Rõ\"õ|õ7õ&
Rõõ	Gõ"ð ñó ðõ0õ
)CðZ ô>ó ð>ð ô*ó ð*÷,ð ,õcõ.õd÷Bbð bð #/°¸ÈÐRXÐZ`Ð!aÐàôó ðõ õ(`õ)sðV ÷Eó ðEõZõ.[õtõ$Tð 	Ð3Ø!Ð#:ØÐ 7Ø!Ð#:ØÐ!5ð7Ðð ôJó ðJð)à9>÷)õF LðD ôSó ðSð ô ó ð õ8=ðt ôIó ðI÷Eð Eð4 ôDó ðDõ^ð>Ø]að>à'+÷>ð@ ôó ðð ôó ðð ôNó ðNð ô=ó ð=õ
ñF€Kð
 ô_ó ð_ð ô9ó ð9õõ:õ õ0õ>õ4õ8!ð HLÐ^q÷Oõy÷
9ð 9ð( #ÐØ"Ðõð  ôPó ðPõH÷ð ñ& CÐ÷Oð Oð, ô4ó ð4ð
 ô@ó ð@õr÷

Yð 
Y÷Tð T÷\ð \ð Ð,¨gÐ7IÈ7ÐTfÐg€Mð5À%÷ 5÷Rð R÷Sð S÷&mð mð !$ÐõQ÷

ð 

÷ð ÷
Uð 
U÷ið i÷ið i÷ið i÷að a÷.Sð .Sõ`4÷,Lð Lõ.Nõ_ð ôAó ðAõ7ð ô8ó ð8÷X÷$ö $r/   rn   )	r  r  r†  rÜ  r‡  ú.m4aú.aacz.speexr…  >   r‘  r  r�  r†  r‡  rÜ  r…  r  )lr5   Ú
__future__r   Úpmr   rÆ   ry  r  ÚloggingrD  rr  r  r¸  r   r   r   Úpathlibr   Útypingr   r	   r
   r   r   r   r   Úurllib.parser   r@  rg   r%  rã  rh   Úgateway.configr   r   Úgateway.platforms.baser   r   r   r   r   r   Úgateway.platforms.eventr   r   Úgateway.platforms.helpersr   r   r   r   Ú%gateway.platforms.access_policy_mixinr   Úgateway.platforms.media_cacher   Ú	getLoggerr1   rÝ   rç   r!   Ú	constantsr9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   rN   ÚutilsrO   rµ   rP   Úchunked_uploadrQ   rR   rS   r   rT   rU   rV   rW   rX   rY   rZ   r[   Úgateway.platforms._sharedr\   r¯   ri   rÑ  r`  rq  rn   rb   r/   r-   Ú<module>r£     sb  ðñõ #å Û Û Û Û Û 	Û 	Û Û ß ,Ñ ,Ý ß H× HÑ HÝ !ðÛØÐð
ÛØ€O÷
 4÷÷ ÷ >Ý 4ß \Ñ \Ý FÝ 6à	×	Ò	˜8Ó	$€ôW�9ô W÷b÷ b÷ b÷ b÷ b÷ b÷ A÷Mñ M÷%÷ %ó %õ Nõ1ð aÐ à	Ð8ð Ð)Ø	Ð8ð:Ð ò [Ð ôb$Ð$Ð&9ö b$øðM ô ØÐØ‚Gðûð ô Ø€OØ‚Eðús$   ÁD< ÁE Ä<E
Å	E
ÅEÅE