+
    iу                       R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHtHtH	t	H
t
 ]P                  ! ]4      t ^ RIHtHtHt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t!^ RI$t$^ RI%H&t' ]$PP                  PS                  ^ ]*! ]'! ]+4      PY                  4       PZ                  ^,          4      4       ^ RI.H/t/H0t0 ^ RI1H2t2H3t3H4t4H5t5H6t6H7t7H8t8H9t9 ^ RI:H;t;H<t<H=t= R R lt>]P~                  ! R4      t@R R ltAR R ltB ! R R]24      tCR#   ]" d,    Rt!]
t]
t]
t]
t]
t]
t]
t]
t]
t]
t RtRtRt ! R	 R
4      t#]#t Li ; i)z
Telegram platform adapter.

Uses python-telegram-bot library for:
- Receiving messages from users/groups
- Sending responses back
- Handling media and commands
N)DictListOptionalAny)UpdateBotMessageInlineKeyboardButtonInlineKeyboardMarkup)ApplicationCommandHandlerCallbackQueryHandlerMessageHandlerContextTypesfilters)	ParseModeChatType)HTTPXRequestTFc                       ] tR t^2t]tRtR# )_MockContextTypes N)__name__
__module____qualname____firstlineno__r   DEFAULT_TYPE__static_attributes__r       7/home/ubuntu/hermes-agent/gateway/platforms/telegram.pyr   r   2   s    r   r   )Path)PlatformPlatformConfig)BasePlatformAdapterMessageEventMessageType
SendResultcache_image_from_bytescache_audio_from_bytescache_document_from_bytesSUPPORTED_DOCUMENT_TYPES)TelegramFallbackTransportdiscover_fallback_ipsparse_fallback_ip_envc                $    V ^8  d   QhR\         /#    returnbool)formats   "r   __annotate__r4   L   s      T r   c                     \         # )z-Check if Telegram dependencies are available.)TELEGRAM_AVAILABLEr   r   r   check_telegram_requirementsr7   L   s    r   z([_*\[\]()~`>#\+\-=|{}.!\\])c                0    V ^8  d   QhR\         R\         /# r/   textr0   str)r3   s   "r   r4   r4   V   s     . .s .s .r   c                .    \         P                  RV 4      # )zIEscape Telegram MarkdownV2 special characters with a preceding backslash.z\\\1)_MDV2_ESCAPE_REsubr:   s   &r   _escape_mdv2rA   V   s    w--r   c                0    V ^8  d   QhR\         R\         /# r9   r;   )r3   s   "r   r4   r4   [   s      c c r   c                    \         P                  ! RRV 4      p\         P                  ! RRV4      p\         P                  ! RRV4      p\         P                  ! RRV4      p\         P                  ! RRV4      pV# )zStrip MarkdownV2 escape backslashes to produce clean plain text.

Also removes MarkdownV2 formatting markers so the fallback
doesn't show stray syntax characters from format_message conversion.
z\\([_*\[\]()~`>#\+\-=|{}.!\\])\1z\*([^*]+)\*z(?<!\w)_([^_]+)_(?!\w)z	~([^~]+)~z\|\|([^|]+)\|\|)rer?   )r:   cleaneds   & r   _strip_mdv2rG   [   sh     ff6tDGff^UG4G ff.w?Gff\5'2Gff'8GNr   c                   0  a a ] tR t^ot oRtRtRtV3R lV 3R lltV3R lR lt]	V3R lR	 l4       t
]	V3R
 lR l4       tV3R lR ltV3R lR ltRmV3R lR lltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltRmV3R lR lltV3R lR ltRnV3R  lR! lltV3R" lR# ltRoV3R$ lV 3R% llltRoV3R& lV 3R' llltRpV3R( lV 3R) llltRoV3R* lV 3R+ llltRoV3R, lV 3R- llltRoV3R. lR/ lltRqV3R0 lR1 lltV3R2 lR3 ltV3R4 lR5 lt V3R6 lR7 lt!V3R8 lR9 lt"V3R: lR; lt#V3R< lR= lt$V3R> lR? lt%V3R@ lRA lt&V3RB lRC lt'V3RD lRE lt(RFRG/V3RH lRI llt)V3RJ lRK lt*V3RL lRM lt+V3RN lRO lt,V3RP lRQ lt-V3RR lRS lt.V3RT lRU lt/V3RV lRW lt0V3RX lRY lt1V3RZ lR[ lt2V3R\ lR] lt3V3R^ lR_ lt4V3R` lRa lt5V3Rb lRc lt6V3Rd lRe lt7V3Rf lRg lt8V3Rh lRi lt9V3Rj lRk lt:Rlt;Vt<V ;t=# )rTelegramAdapterz
Telegram bot adapter.

Handles:
- Receiving messages from users and groups
- Sending responses with Telegram markdown
- Forum topics (thread_id support)
- Media messages
i   g?c                    < V ^8  d   QhRS[ /# )r/   config)r!   )r3   __classdict__s   "r   r4   TelegramAdapter.__annotate__~   s     ^ ^~ ^r   c                b  < \         SV `  V\        P                  4       R V n        R V n        RV n        V P                  4       V n        \        VRR4      ;'       g    RV n
        \        \        P                  ! RR4      4      V n        / V n        / V n        / V n        / V n        \        \        P                  ! RR4      4      V n        / V n        / V n        R V n        R V n        ^ V n        ^ V n        R V n        / V n        V P8                  P:                  P=                  R. 4      V n        R # )	NFreply_to_modefirst)HERMES_TELEGRAM_MEDIA_BATCH_DELAY_SECONDSz0.8(HERMES_TELEGRAM_TEXT_BATCH_DELAY_SECONDSz0.6	dm_topics) super__init__r    TELEGRAM_app_bot_webhook_mode_compile_mention_patterns_mention_patternsgetattr_reply_to_modefloatosgetenv_media_batch_delay_seconds_pending_photo_batches_pending_photo_batch_tasks_media_group_events_media_group_tasks_text_batch_delay_seconds_pending_text_batches_pending_text_batch_tasks_token_lock_identity_polling_error_task_polling_conflict_count_polling_network_error_count_polling_error_callback_ref
_dm_topicsrK   extraget_dm_topics_config)selfrK   	__class__s   &&r   rU   TelegramAdapter.__init__~   s   !2!23+/	#'	#(!%!?!?!A#*6?G#L#W#WPW +0		:egl0m*n'?A#CE'<> ;= */ryy9cej/k)l&>@"BD&37!;? ,-$12)+/(*,7;{{7H7H7L7L[Z\7]r   c                0   < V ^8  d   QhRS[ S[,          /# r.   )listr<   )r3   rL   s   "r   r4   rM      s     c ctCy cr   c                8   \        V P                  RR4      '       d'   V P                  P                  P                  R. 4      M. p\	        V\
        4      '       d   VP                  R4      p\        V'       d   RP                  R V 4       4      4      # R4      # )zNReturn validated fallback IPs from config (populated by _apply_env_overrides).ro   Nfallback_ips,c              3   8   "   T F  p\        V4      x  K  	  R # 5iNr;   ).0vs   & r   	<genexpr>0TelegramAdapter._fallback_ips.<locals>.<genexpr>   s     -Ijc!ffjs   )	r\   rK   ro   rp   
isinstancer<   splitr,   joinrr   
configureds   & r   _fallback_ipsTelegramAdapter._fallback_ips   sw    BI$++W^`dBeBeT[[&&**>2>km
j#&&#))#.J$ZSXX-Ij-I%Ibb]abbr   c                &   < V ^8  d   QhRS[ RS[/# r/   errorr0   	Exceptionr2   )r3   rL   s   "r   r4   rM      s     
 
I 
$ 
r   c                    \        V 4      P                  4       pV P                  P                  P                  4       R 8H  ;'       g    RV9   ;'       g    RV9   # )conflictz&terminated by other getupdates requestzanother bot instance is running)r<   lowerrs   r   )r   r:   s   & r   _looks_like_polling_conflict,TelegramAdapter._looks_like_polling_conflict   sX    5z!OO$$**,
: 9 974?9 90D8	
r   c                &   < V ^8  d   QhRS[ RS[/# r   r   )r3   rL   s   "r   r4   rM      s     * * *t *r   c                    V P                   P                  P                  4       pVR9   d   R#  ^ RIHpHp \        WV34      '       d   R#  \        V \        4      #   \         d     Li ; i)zJReturn True for transient network errors that warrant a reconnect attempt.TNetworkErrorTimedOut)networkerrortimedoutconnectionerror)	rs   r   r   telegram.errorr   r   r   ImportErrorOSError)r   namer   r   s   &   r   _looks_like_network_error)TelegramAdapter._looks_like_network_error   sk     ''--/BB	=%!9:: ; %))  		s   A A+*A+c                $   < V ^8  d   QhRS[ RR/# r/   r   r0   Nr   )r3   rL   s   "r   r4   rM      s#     AG AG AGt AGr   c                  "   V P                   '       d   R# ^
p^p^<pV ;P                  ^,          un        V P                  pWR8  dY   RV,          p\        P                  RV P                  Wa4       V P                  RVRR7       V P                  4       G Rj  xL
  R# \        V^V^,
          ,          ,          V4      p\        P                  RV P                  WRWq4       \        P                  ! V4      G Rj  xL
   V P                  '       do   V P                  P                  '       dS   V P                  P                  P                  '       d-   V P                  P                  P                  4       G Rj  xL
   T P                  P                  P!                  \"        P$                  RT P&                  R	7      G Rj  xL
  \        P)                  R
T P                  T4       ^ T n        R#  EL\ L L|  \         d     Li ; i LF  \         d   p\        P                  RT P                  T4       T P                   '       gl   \        P*                  ! T P-                  T4      4      p	T P.                  P1                  T	4       T	P3                  T P.                  P4                  4        Rp?R#  Rp?R# Rp?ii ; i5i)a  Reconnect polling after a transient network interruption.

Triggered by NetworkError/TimedOut in the polling error callback, which
happen when the host loses connectivity (Mac sleep, WiFi switch, VPN
reconnect, etc.).  The gateway process stays alive but the long-poll
connection silently dies; without this handler the bot never recovers.

Strategy: exponential back-off (5s, 10s, 20s, 40s, 60s cap) up to
MAX_NETWORK_RETRIES attempts, then mark the adapter retryable-fatal so
the supervisor restarts the gateway process.
NzXTelegram polling could not reconnect after %d network error retries. Restarting gateway.z[%s] %s Last error: %stelegram_network_errorT	retryablezK[%s] Telegram network error (attempt %d/%d), reconnecting in %ds. Error: %sFallowed_updatesdrop_pending_updateserror_callbackz>[%s] Telegram polling resumed after network error (attempt %d)z*[%s] Telegram polling reconnect failed: %s)has_fatal_errorrl   loggerr   r   _set_fatal_error_notify_fatal_errorminwarningasynciosleeprW   updaterrunningstopr   start_pollingr   	ALL_TYPESrm   infoensure_future_handle_polling_network_error_background_tasksaddadd_done_callbackdiscard)
rr   r   MAX_NETWORK_RETRIES
BASE_DELAY	MAX_DELAYattemptmessagedelay	retry_errtasks
   &&        r   r   -TelegramAdapter._handle_polling_network_error   sK      
	))Q.)33(&(;<  LL1499gM!!":Gt!T**,,,J!!"45yAYIIwU	
 mmE"""	yyyTYY...4993D3D3L3L3Lii'',,...	G))##11 & 0 0%*#?? 2   
 KKP		7 12D-5 - 	# / 		  		GNNGT]^ ''',,66yA &&**40&&t'='='E'EFF (			Gs   BKG5A"K<G8=KG< G< 0%G< 'G< =G:>G< AH H,H 3K8K:G< <H
K	H

KH KBJ>2K>KKc                $   < V ^8  d   QhRS[ RR/# r   r   )r3   rL   s   "r   r4   rM      s     6) 6)I 6)$ 6)r   c                  "   V P                   '       d   V P                  R 8X  d   R# V ;P                  ^,          un        ^p^
pV P                  V8:  EdJ   \        P	                  RV P
                  V P                  VW14        V P                  '       do   V P                  P                  '       dS   V P                  P                  P                  '       d-   V P                  P                  P                  4       G Rj  xL
  \        P                  ! T4      G Rj  xL
   T P                  P                  P                  \        P                  RT P                   R7      G Rj  xL
  \        P#                  RT P
                  T P                  4       ^ T n        R# RV,          p\        P%                  RV P
                  WQ4       V P'                  R VRR	7        V P                  '       dI   V P                  P                  '       d-   V P                  P                  P                  4       G Rj  xL
  T P)                  4       G Rj  xL
  R#  ELS  \         d     EL_i ; i ELJ EL  \         d-   p\        P	                  RT P
                  T4        Rp?R# Rp?ii ; i Ls  \         d.   p\        P	                  R
T P
                  TRR7        Rp?LRp?ii ; i L5i)telegram_polling_conflictNzD[%s] Telegram polling conflict (%d/%d), will retry in %ds. Error: %sFr   z5[%s] Telegram polling resumed after conflict retry %dz&[%s] Telegram polling retry failed: %szAnother Telegram bot poller is already using this token. Hermes stopped Telegram polling after %d retries. Make sure only one gateway instance is running for this bot token.z[%s] %s Original error: %sr   z8[%s] Failed stopping Telegram polling after conflict: %sTexc_info)r   fatal_error_coderk   r   r   r   rW   r   r   r   r   r   r   r   r   r   rm   r   r   r   r   )rr   r   MAX_CONFLICT_RETRIESRETRY_DELAYr   r   
stop_errors   &&     r   _handle_polling_conflict(TelegramAdapter._handle_polling_conflict   sZ    D$9$9=X$X 	$$)$ ''+??NNV		4779M
999!2!2!2tyy7H7H7P7P7P))++00222 --,,,ii''55$*$4$4).#'#C#C 6   
 SUYU^U^`d`|`|}/0,Q ## 	 	1499gM97eT	}yyyTYY...ii'',,... &&(((C 3 ,  GT]^ 	" / 	}NNUW[W`W`blw{N||	}(s   BK'-I 3%I 'I  II K'I(K'$AI. 'I+(6I. A K'-J* 'J* 4J(5J* 9K'K%K'I I%!K'$I%%K'+I. .J%9!J K' J%%K'(J* *K"5#KK'K""K'c                h   < V ^8  d   QhRS[ RS[RS[S[ ,          RS[S[,          RS[S[ ,          /# )r/   chat_idr   
icon_coloricon_custom_emoji_idr0   )intr<   r   )r3   rL   s   "r   r4   rM   4  sI     * ** * SM	*
 'sm* 
#*r   c                  "   V P                   '       g   R#  RVRV/pVe   W5R&   V'       d   WER&   V P                   P                  ! R/ VB G Rj  xL
 pVP                  p\        P	                  RV P
                  W!V4       V#  L4  \         dw   p\        T4      P                  4       p	RT	9   g   RT	9   d#   \        P	                  R	T P
                  Y!4       M"\        P                  R
T P
                  Y!T4        Rp?R# Rp?ii ; i5i)zCreate a forum topic in a private (DM) chat.

Uses Bot API 9.4's createForumTopic which now works for 1-on-1 chats.
Returns the message_thread_id on success, None on failure.
Nr   r   r   r   z5[%s] Created DM topic '%s' in chat %s -> thread_id=%stopic_name_duplicatealreadyzT[%s] DM topic '%s' already exists in chat %s (will be mapped from incoming messages)z2[%s] Failed to create DM topic '%s' in chat %s: %sr   )
rX   create_forum_topicmessage_thread_idr   r   r   r   r<   r   r   )
rr   r   r   r   r   kwargstopic	thread_ide
error_texts
   &&&&&     r   _create_dm_topic TelegramAdapter._create_dm_topic4  s      yyy	&/&$%GF%'1|$#1E-.))66@@@E//IKKG		4)  A  	QJ &3yJ7NjIIt
 HIIta 	sF   DB #B B3B DB D	A+D>DD		Dc                0   < V ^8  d   QhRS[ RS[RS[ RR/# )r/   r   
topic_namer   r0   N)r   r<   )r3   rL   s   "r   r4   rM   `  s1     )j )j3 )jC )jTW )j\` )jr   c           	     >    ^ RI Hp V! 4       R,          pVP                  4       '       g$   \        P	                  RV P
                  V4       R# ^ RIp\        VR4      ;_uu_ 4       pVP                  V4      ;'       g    / pRRR4       XP                  R/ 4      P                  R/ 4      P                  R/ 4      P                  R	. 4      p	V	'       g   R# R
p
V	 F  p\        VP                  R^ 4      4      \        V4      8w  d   K.  VP                  R. 4       F;  pVP                  R4      V8X  g   K  VP                  R4      '       d   K4  W<R&   Rp
 K}  	  K  	  V
'       dU   \        VR4      ;_uu_ 4       pVP                  WR
R
R7       RRR4       \        P                  RV P
                  W24       R# R#   + '       g   i     ELB; i  + '       g   i     LI; i  \         d/   p\        P	                  RT P
                  TRR7        Rp?R# Rp?ii ; i)zTSave a newly created thread_id back into config.yaml so it persists across restarts.get_hermes_homeconfig.yamlz:[%s] Config file not found at %s, cannot persist thread_idNr	platformstelegramro   rS   Fr   topicsr   r   Tw)default_flow_style	sort_keysz9[%s] Persisted thread_id=%s for topic '%s' in config.yamlz.[%s] Failed to persist thread_id to config: %sr   )hermes_constantsr   existsr   r   r   yamlopen	safe_loadrp   r   dumpr   r   )rr   r   r   r   r   config_path_yamlfrK   rS   changed
chat_entrytr   s   &&&&          r   _persist_dm_topic_thread_id+TelegramAdapter._persist_dm_topic_thread_id`  s   '	j8)+m;K%%''[]a]f]fhst k3''1+11r (
 

;+Z$Wb!["%	  G'
z~~i34GD#"5AuuV}
2155;M;M)2+"&	 6 ( +s++qJJvUeJT ,OIIy / (''0 ,+  	jNNKTYYXYdhNii	jsl   )G# !G# G# 'F<AG# AG# 6G# G# &G# :G)G# <G		G# G 	G# #H.#HHc                   < V ^8  d   QhRR/# r/   r0   Nr   )r3   rL   s   "r   r4   rM     s     DZ DZ DZr   c           	     ^  "   V P                   '       g   R# V P                    EF  pVP                  R4      pVP                  R. 4      pV'       d	   V'       g   K9  \        P                  RV P                  \        V4      V4       V EF  pVP                  R4      pV'       g   K  V RV 2pVP                  R4      pV'       d<   \        V4      V P                  V&   \        P                  RV P                  Wg4       Kz  VP                  R	4      pVP                  R
4      p	V P                  \        V4      VVV	R7      G Rj  xL
 p
V
'       g   K  WP                  V&   \        P                  RV P                  Wj4       V P                  \        V4      WZ4       EK  	  EK  	  R#  Ld5i)u  Load or create configured DM topics for specified chats.

Reads config.extra['dm_topics'] — a list of dicts:
[
    {
        "chat_id": 123456789,
        "topics": [
            {"name": "General", "icon_color": 7322096, "thread_id": 100},
            {"name": "Accessibility Auditor", "icon_color": 9367192, "skill": "accessibility-auditor"}
        ]
    }
]

If a topic already has a thread_id in the config (persisted from a previous
creation), it is loaded into the cache without calling createForumTopic.
Only topics without a thread_id are created via the API, and their thread_id
is then saved back to config.yaml for future restarts.
Nr   r   z*[%s] Setting up %d DM topic(s) for chat %sr   :r   z4[%s] DM topic loaded from config: %s -> thread_id=%sr   r   )r   r   r   r   z([%s] DM topic cached: %s -> thread_id=%s)
rq   rp   r   r   r   lenr   rn   r   r   )rr   r   r   r   
topic_confr   	cache_keyexisting_thread_idr   
icon_emojir   s   &          r   _setup_dm_topics TelegramAdapter._setup_dm_topics  sp    & %%%00J nnY/G^^Hb1F&KK<		3v;
 %
'^^F3
!&iq5	 &0^^K%@"%145G1HDOOI.KKN		9  (^^L9
'^^,BC
"&"7"7L#))3	 #8 # 	 91:OOI.KKB		9
 44S\:YG % 1@s'   AF-A-F-A>F-F+	F-AF-c                    < V ^8  d   QhRS[ /# r.   r1   )r3   rL   s   "r   r4   rM     s     \ \t \r   c           
     *  a a""   \         '       g#   \        P                  RS P                  4       R# S P                  P
                  '       g#   \        P                  RS P                  4       R#  ^ RIHp S P                  P
                  S n        V! RS P                  RS P                  P                  /R7      w  r#V'       g   \        V\        4      '       d   VP                  R4      MR	pR
V'       d   RV R2MR,           R,           p\        P                  RS P                  V4       S P                  RVRR7       R# \        P                   ! 4       P                  S P                  P
                  4      pS P#                  4       pV'       gC   \%        4       G R	j  xL
 p\        P'                  RS P                  RP)                  V4      4       V'       dx   \        P'                  RS P                  RP)                  V4      4       \+        V4      p\-        RV/R7      p	\-        RV/R7      p
VP/                  V	4      P1                  V
4      pTP3                  4       S n        S P4                  P6                  S n        S P4                  P;                  \=        \>        P@                  \>        PB                  ( ,          S PD                  4      4       S P4                  P;                  \=        \>        PB                  S PF                  4      4       S P4                  P;                  \=        \>        PH                  \K        \>        R\>        PH                  4      ,          S PL                  4      4       S P4                  P;                  \=        \>        PN                  \>        PP                  ,          \>        PR                  ,          \>        PT                  ,          \>        PV                  PX                  ,          \>        PZ                  PX                  ,          S P\                  4      4       S P4                  P;                  \_        S P`                  4      4        ^ RI1H2pH3p ^p\m        V4       F&  p S P4                  Po                  4       G R	j  xL
   M	  S P4                  Pw                  4       G R	j  xL
  \x        Pz                  ! RR4      P}                  4       pV'       d   \        \x        Pz                  ! RR4      4      p\x        Pz                  ! RR4      P}                  4       ;'       g    R	p^ RI@HAp V! V4      P                  ;'       g    R pS P4                  P                  P                  R!VVVV\        P                  R"R#7      G R	j  xL
  R"S nG        \        P'                  R$S P                  VV4       M\K        S P8                  R%R	4      p\        V4      '       d   V! RR&7      G R	j  xL
  \r        P                  ! 4       o"R' V"V 3R( llpVS nJ        S P4                  P                  P                  \        P                  R"VR)7      G R	j  xL
   ^ R*ILHMp ^ R+INHOp V! ^dR,7      w  ppS P8                  P                  V UUu. uF  w  ppV! VV4      NK  	  upp4      G R	j  xL
  V'       d,   \        P'                  R-S P                  \        V4      V4       S P                  4        S P                  '       d   R0MR1p\        P'                  R2S P                  T4        S P                  4       G R	j  xL
  R"#  EL  \h         d    \j        ;r ELi ; i EL  Y\j        3 dm   pY^,
          8  dZ   ^T,          p\        Pq                  RS P                  T^,           YT4       \r        Pt                  ! T4      G R	j  xL 
   R	p?EKr  h R	p?ii ; i EL4 ELW EL ELu uppi  ELG  \         d/   p\        Pq                  R.S P                  TR"R/7        R	p?ELFR	p?ii ; i L  \         d/   p \        Pq                  R3S P                  T R"R/7        R	p ? R"# R	p ? ii ; i  \         d   pS P                  '       d-    ^ R4IHUp! T!! RS P                  4       M  \         d     Mi ; iR5T 2pS P                  R6TR"R7       \        P                  R7S P                  TR"R/7        R	p?R# R	p?ii ; i5i)8a  Connect to Telegram via polling or webhook.

By default, uses long polling (outbound connection to Telegram).
If ``TELEGRAM_WEBHOOK_URL`` is set, starts an HTTP webhook server
instead.  Webhook mode is useful for cloud deployments (Fly.io,
Railway) where inbound HTTP can wake a suspended machine.

Env vars for webhook mode::

    TELEGRAM_WEBHOOK_URL    Public HTTPS URL (e.g. https://app.fly.dev/telegram)
    TELEGRAM_WEBHOOK_PORT   Local listen port (default 8443)
    TELEGRAM_WEBHOOK_SECRET Secret token for update verification
zL[%s] python-telegram-bot not installed. Run: pip install python-telegram-botFz[%s] No bot token configured)acquire_scoped_locktelegram-bot-tokenplatform)metadatapidNzEAnother local Hermes gateway is already using this Telegram bot tokenz (PID z)..zA Stop the other gateway before starting a second Telegram poller.z[%s] %stelegram_token_lockr   z.[%s] Auto-discovered Telegram fallback IPs: %s, z%[%s] Telegram fallback IPs active: %s	transport)httpx_kwargsVENUEr   u9   [%s] Connect attempt %d/%d failed: %s — retrying in %dsTELEGRAM_WEBHOOK_URL TELEGRAM_WEBHOOK_PORT8443TELEGRAM_WEBHOOK_SECRET)urlparsez	/telegramz0.0.0.0T)listenporturl_pathwebhook_urlsecret_tokenr   r   z-[%s] Webhook server listening on 0.0.0.0:%d%sdelete_webhook)r   c                (    V ^8  d   QhR\         RR/# r   r   )r3   s   "r   r4   -TelegramAdapter.connect.<locals>.__annotate__d  s     	i 	i9 	i 	ir   c                   < SP                   '       d#   SP                   P                  4       '       g   R # SP                  V 4      '       d(   SP                  SP	                  V 4      4      Sn         R # SP                  V 4      '       dI   \        P                  RSP                  V 4       SP                  SP                  V 4      4      Sn         R # \        P                  RSP                  V RR7       R # )Nz5[%s] Telegram network error, scheduling reconnect: %sz[%s] Telegram polling error: %sTr   )rj   doner   create_taskr   r   r   r   r   r   r   )r   looprr   s   &r   _polling_error_callback8TelegramAdapter.connect.<locals>._polling_error_callbackd  s    ///8P8P8U8U8W8W88??373C3CDDaDabgDh3i077>>'^`d`i`ikpq373C3CDDfDfglDm3n0%F		SXcghr   r   )
BotCommand)telegram_menu_commands)max_commandszd[%s] Telegram menu: %d commands registered, %d hidden (over 100 limit). Use /commands for full list.z1[%s] Could not register Telegram command menu: %sr   webhookpollingz$[%s] Connected to Telegram (%s mode)z+[%s] DM topics setup failed (non-fatal): %srelease_scoped_lockzTelegram startup failed: telegram_connect_errorz&[%s] Failed to connect to Telegram: %s)Vr6   r   r   r   rK   tokengateway.statusr  ri   r  valuer   dictrp   r   r   builderr   r+   r   r   r*   r   requestget_updates_requestbuildrW   botrX   add_handlerTelegramMessageHandlerr   TEXTCOMMAND_handle_text_message_handle_commandLOCATIONr\   _handle_location_messagePHOTOVIDEOAUDIOVOICEDocumentALLSticker_handle_media_messager   _handle_callback_queryr   r   r   r   r   range
initializer   r   r   startr_   r`   stripr   urllib.parser  pathr   start_webhookr   r   rY   callableget_running_looprm   r   r   r*  hermes_cli.commandsr+  set_my_commandsr  r   _mark_connectedr  r0  )#rr   r  acquiredexisting	owner_pidr   r6  rx   r  r7  r8  r   r   _max_connect_attemptinit_errwaitr  webhook_portwebhook_secretr  webhook_pathr!  r(  r*  r+  menu_commandshidden_countr   descr   mode
topics_errr0  r'  s#   f                                 @r   connectTelegramAdapter.connect  sV     "!LL^		 {{   LL7CC	:(,(9(9D%!4$))$dmm&9&9:"H
 3=h3M3MHLL/SW	[1:	{"-EYZ 
 Y		7;%%&;WPU%V "))+11$++2C2CDG--/L%:%<<DIIIIl+
 ;IIIIl+
 6lC	&[)4LM&2i@X&Y#!//'2FFGZ[DI		DI II!!"8//))#  II!!"8$$#  II!!"8  77GW=M=M#NN--#  II!!"8-=MPWP`P`PdPddgngvgvgzgzz**# 
 II!!"6t7R7R"ST2A L!,/))..000 0 ))//### ))$:B?EEGK
  #299-Df#MN!#+Db!I!O!O!Q!Y!YUY1'499HH[ii''55$%) +!/$*$4$4)- 6    &*"CII|\ ")4Dd!KN++(eDDD//1	i 	i 4K0ii''55$*$4$4)-#: 6   /F /ERU.V+|ii//=J1=JztTJtT*]1     KK~		3}#5|   " $ 2 2 29	DKK>		4P
++---   =T  2*11x2
 1$8 	"22 H}W IIx!|\T &mmD1111	 $( E$ 1   GII!	     . AIIzD   
   
	(((B'(<d>W>WX  1!5G!!":Gt!TLLA499aZ^L_
	s  A
d"d2Bb  :A
b  dAb  b  #]$;b   J b  !] )b  :]5]2]5!b  =_1>0b  /Ab  ;!b  A b  _4A"b   _7A#b  $_:%b  *2` _=
1` <`=` 	+` 4!b  %b  <a aa db  ]/+b  .]//b  2]55_.A_)__)!b  (_))_..b  4b  7b  :b  =` `?#`:4b  :`??b  a a=#a82b  6d8a==b   ddb87d8cdc?ddddc                   < V ^8  d   QhRR/# r   r   )r3   rL   s   "r   r4   rM     s     %B %B$ %Br   c                  "   \        V P                  P                  4       4      pV F  pVP                  4        K  	  V'       d   \        P
                  ! VRR/ G Rj  xL
  V P                  P                  4        V P                  P                  4        V P                  '       d    V P                  P                  '       dS   V P                  P                  P                  '       d-   V P                  P                  P                  4       G Rj  xL
  V P                  P                  '       d#   V P                  P                  4       G Rj  xL
  V P                  P                  4       G Rj  xL
  V P"                  '       d    ^ RIHp V! RV P"                  4       V P(                  P                  4        F5  pV'       g   K  VP+                  4       '       d   K%  VP                  4        K7  	  V P(                  P                  4        V P,                  P                  4        V P/                  4        RV n        RV n        RV n        \        P3                  R	V P                   4       R#  EL ELb EL' EL  \         d/   p\        P                  RT P                   TRR7        Rp?EL:Rp?ii ; i  \         d/   p\        P                  RT P                   TRR7        Rp?ELJRp?ii ; i5i)
zCStop polling/webhook, cancel pending album flushes, and disconnect.return_exceptionsTNz)[%s] Error during Telegram disconnect: %sr   r/  r  z,[%s] Error releasing Telegram token lock: %sz[%s] Disconnected from Telegram)rv   re   valuescancelr   gatherclearrd   rW   r   r   r   shutdownr   r   r   r   ri   r3  r0  rc   r%  rb   _mark_disconnectedrX   r   )rr   pending_media_group_tasksr   r   r0  s   &    r   
disconnectTelegramAdapter.disconnect  s"    $()@)@)G)G)I$J!-DKKM .$..";TtTTT%%'  &&(999i99$$$):):)B)B)B))++0022299$$$))..***ii((*** $$$l>#$8$:S:ST 33::<DtDIIKK = 	''--/##))+!		$(!5tyyA? U 3** iJDIIWXcghhi  lMtyyZ[fjkkls   AK8K8 I4!A	K8,J  %J  .'J  I7J  6J  I:!J  5I=6J  :K8J< &"K8K8%BK87J  :J  =J   J9#J4.K84J99K8<K5#K0*K80K55K8c                <   < V ^8  d   QhRS[ S[,          RS[RS[/# )r/   reply_tochunk_indexr0   )r   r<   r   r2   )r3   rL   s   "r   r4   rM     s'     $ $Xc] $ $QU $r   c                \    V'       g   R# V P                   pVR8X  d   R# VR8X  d   R# V^ 8H  # )a  Determine if this message chunk should thread to the original message.

Args:
    reply_to: The original message ID to reply to
    chunk_index: Index of this chunk (0 = first chunk)

Returns:
    True if this chunk should be threaded to the original message
FoffallT)r]   )rr   rv  rw  re  s   &&& r   _should_thread_reply$TelegramAdapter._should_thread_reply  s4     ""5=U]!##r   c                n   < V ^8  d   QhRS[ RS[ RS[S[ ,          RS[S[S[ S[3,          ,          RS[/# )r/   r   contentrv  r  r0   r<   r   r   r   r%   )r3   rL   s   "r   r4   rM     s\     UU UUUU UU 3-	UU
 4S>*UU 
UUr   c                
  "   V P                   '       g   \        RRR7      # V'       d   VP                  4       '       g   \        RRR7      #  V P                  V4      pV P	                  WPP
                  4      p\        V4      ^8  d(   V Uu. uF  p\        P                  ! RRV4      NK  	  pp. pV'       d   VP                  R	4      MRp	 ^ R
I
Hp
  ^ RI
Hp  ^ RI
Hp \#        V4       F  w  rV P%                  W=4      pV'       d   \'        V4      MRpV	'       d   \'        V	4      MRpRp\)        ^4       FD  p  V P                   P+                  \'        V4      V\,        P.                  VVR7      G Rj  xL
 p M	  VPI                  \3        VPJ                  4      4       K  	  \        RV'       d
   V^ ,          MRRV/R7      # u upi   \         d    \        p
 ELi ; i  \         d    Rp ELi ; i  \        \         3 d    Rp EL0i ; i L  \0         d   pR\3        T4      P5                  4       9   g   R\3        T4      P5                  4       9   de   \6        P9                  RT P:                  T4       \=        T4      pT P                   P+                  \'        T4      TRTTR7      G Rj  xL 
 p Rp?ELEh Rp?ii ; i  T
 Ed    pT'       d   \?        TT4      '       d   \3        T4      P5                  4       pRT9   d/   Te+   \6        P9                  RT P:                  T4       Rp Rp?EK  RT9   d/   Te+   \6        P9                  RT P:                  T4       Rp Rp?EK7  h T'       d   \?        TT4      '       d   h T^8  dZ   ^T,          p\6        P9                  RT P:                  T^,           TT4       \@        PB                  ! T4      G Rj  xL 
   Rp?EK  h Rp?i\0         d   p\E        TRR4      pTf   R\3        T4      P5                  4       9   di   T^8  db   Te   \G        T4      MRp\6        P9                  RT P:                  T^,           TT4       \@        PB                  ! T4      G Rj  xL 
   Rp?EKY  h Rp?ii ; i  \0         d   p\6        PM                  RT P:                  TRR7       \O        4       P                  R4      p\3        T4      P5                  4       pT;'       d    \?        TT4      ;'       g    RT9   p\        R\3        T4      T'       * R 7      u Rp?# Rp?ii ; i5i)!z"Send a message to a Telegram chat.FNot connectedsuccessr   TNr  
message_idz \((\d+)/(\d+)\)$z \\(\1/\2\\)r   )r   )
BadRequest)r   )r   r:   
parse_modereply_to_message_idr   parsemarkdownz<[%s] MarkdownV2 parse failed, falling back to plain text: %szthread not foundz<[%s] Thread %s not found, retrying without message_thread_idzmessage to be replied not foundz8[%s] Reply target deleted, retrying without reply_to: %sz>[%s] Network error on send (attempt %d/3), retrying in %ds: %sretry_afterretry after      ?zI[%s] Telegram flood control on send (attempt %d/3), retrying in %.1fs: %smessage_ids)r  r  raw_responsez([%s] Failed to send Telegram message: %sr   	_TimedOutz	timed out)r  r   r   )(rX   r%   rO  format_messagetruncate_messageMAX_MESSAGE_LENGTHr  rE   r?   rp   r   r   r   r   r  r   AttributeError	enumerater{  r   rL  send_messager   MARKDOWN_V2r   r<   r   r   r   r   rG   r   r   r   r\   r^   appendr  r   locals)rr   r   r~  rv  r  	formattedchunkschunkr  r   _NetErr_BadReqr  ishould_threadreply_to_ideffective_thread_idmsg_send_attemptmd_errorplain_chunksend_err	err_lowerr^  r  r   _toerr_str
is_timeouts   &&&&&                        r   sendTelegramAdapter.send  s     yyye?CC gmmoodt<<F	U++G4I**96M6MNF6{Q "(!' FF/%H!'  
 K5=[14I"B@!@ &f- $ 9 9( F/<c(m$8Ac)nt#%*1XMP&(,		(>(>(+G%*+4+@+@4?2E )? ) #C* 3 &.d ""3s~~#67q .t -8;q>d+[9 c  "!"
  
  0 ! 	!#  ) &&#h-*=*=*??:QTU]Q^QdQdQfCf &/mosoxox  {C  !D.9%.@,0II,B,B,/L)4/38C6I -C -" '" '" !&& # ("
 #z(G'D'D(+H(;(;(=I1Y>CVCb !'$b$(II/B!" 7; 3 (@IMR]Ri !'$^$(IIx!" /3 (! %Hi)H)H!(1,#$#5D"NN+k+/99ma6GxY")--"5555!$ &-ht&L&2ms8}GZGZG\6\,q0=H=Tu['9Z] &$o$(II$1A$5$($,!" '.mmD&9 9 9 (.  	ULLCTYYPQ\`La (,,{+C!fllnG44*Q"4OO9OJe3q6^TT	Us  'U	U	 U	A R !G/R ;R G G) G= #=R !R  :H:H;H?AR U	R G&"R %G&&R )G:6R 9G::R =HR HR HK
$BK8J;
9K>KKK

KRA!O/6R =.O/+R 2O/;A&O/!O$
"O/'R .O//R<R=B
RR

RR RRR U(A1U!U;U<U	UU	c                2   < V ^8  d   QhRS[ RS[ RS[ RS[/# )r/   r   r  r~  r0   r<   r%   )r3   rL   s   "r   r4   rM     s9     Q; Q;Q; Q; 	Q;
 
Q;r   c           	     z  "   V P                   '       g   \        RRR7      #  V P                  V4      p V P                   P                  \	        V4      \	        V4      V\
        P                  R7      G Rj  xL
  \        RVR7      #  L  \         dt   pR\        T4      P                  4       9   d   \        RTR7      u Rp?# T P                   P                  \	        T4      \	        T4      TR	7      G Rj  xL 
   Rp?LRp?ii ; i  \         Ed!   p\        T4      P                  4       pRT9   d   \        RTR7      u Rp?# R
T9   g   RT9   d|   TRT P                  ^,
           R,           p T P                   P                  \	        T4      \	        T4      TR	7      G Rj  xL 
  M  \         d     Mi ; i\        RTR7      u Rp?# \        TRR4      p	T	f	   RT9   Ed	   T	'       d   T	MRp
\        P                  RT P                  T
4       T
R8  d   \        RRT
 2R7      u Rp?# \        P                   ! T
4      G Rj  xL 
   T P                   P                  \	        T4      \	        T4      TR	7      G Rj  xL 
  \        RTR7      u Rp?#   \         dG   p\        P#                  RT P                  T4       \        R\        T4      R7      u Rp?u Rp?# Rp?ii ; i\        P#                  RT P                  TTRR7       \        R\        T4      R7      u Rp?# Rp?ii ; i5i)z(Edit a previously sent Telegram message.Fr  r  )r   r  r:   r  Nznot modifiedTr  )r   r  r:   message_too_longztoo longu   …r  r  r  z*[%s] Telegram flood control, waiting %.1fsg      @zflood_control:z+[%s] Edit retry failed after flood wait: %sz+[%s] Failed to edit Telegram message %s: %sr   )rX   r%   r  edit_message_textr   r   r  r   r<   r   r  r\   r   r   r   r   r   r   )rr   r   r  r~  r  fmt_errr   r  	truncatedr  r^  r   s   &&&&        r   edit_messageTelegramAdapter.edit_message  s     yyye?CCH	;++G4Iii11L":"(44	 2     dzBB!  	!S\%7%7%99%dzJJii11L":  2   	  4	;!fllnG(!$:FF "W,
g0E#$Bd&=&=&BCeK	))55 #G#&z?& 6   
 ! !$:FF "!]D9K&-7*B&1{s@IIt #:%e^D6;RSSmmD)))K))55 #G#&z?$ 6   
 &dzJJ  KLLE		9 &e3y>JJJK LL=		   e3q6::i4	;sZ   L;D AB 7B	8B <D L;	B D	*D D	D L;3D9C<:D?D D		D L8,L3L8L;
+L363F0)F,*F0/L30F>;L3=F>>L3L8L; L34;L3/L80L;5L3IL33J J	J L8L; K1+6K,!K1"L3&L8'L;,K11<L3-L8.L;3L88L;c          
      8   < V ^8  d   QhRS[ RS[ RS[ RS[ RS[/# )r/   r   promptdefaultsession_keyr0   r  )r3   rL   s   "r   r4   rM     s7     ; ;;$';25;; 
;r   c                  "   V P                   '       g   \        RRR7      #  V'       d   RV R2MRpRV V 2p\        \        RR	R
7      \        RRR
7      ..4      pV P                   P	                  \        V4      V\        P                  VR7      G Rj  xL
 p\        R\        VP                  4      R7      #  L$  \         dB   p	\        P                  RT P                  T	4       \        R\        T	4      R7      u Rp	?	# Rp	?	ii ; i5i)zSend an inline-keyboard update prompt (Yes / No buttons).

Used by the gateway ``/update`` watcher when ``hermes update --gateway``
needs user input (stash restore, config migration).
Fr  r  z (default: )r  u    ⚕ *Update needs your input:*

u   ✓ Yeszupdate_prompt:y)callback_datau   ✗ Nozupdate_prompt:n)r   r:   r  reply_markupNTr  z"[%s] send_update_prompt failed: %s)rX   r%   r
   r	   r  r   r   MARKDOWNr<   r  r   r   r   r   )
rr   r   r  r  r  default_hintr:   keyboardr  r   s
   &&&&&     r   send_update_prompt"TelegramAdapter.send_update_prompt  s      yyye?CC	;7>[	3BL7x~ND+(BST(ARS- H 		..G$--%	 /  C ds3>>7JKK  	;NN?ANe3q6::	;sL    DB> A,B> B<#B> ;D<B> >D
	6D?D
 DD

Dc                &   < V ^8  d   QhRRRRRR/# )r/   updater   contextzContextTypes.DEFAULT_TYPEr0   Nr   )r3   rL   s   "r   r4   rM     s*     !S !S!S)D!S	!Sr   c           	       "   VP                   pV'       d   VP                  '       g   R# VP                  pVP                  R4      '       g   R# VP                  R^4      ^,          pVP	                  RV R2R7      G Rj  xL
  VR8X  d   RMR	p VP                  R
V R2\        P                  RR7      G Rj  xL
   ^ RI	H
p V! 4       pVR,          p	V	P                  R4      p
V
P                  V4       V
P                  V	4       \        P                  RV\!        VP"                  RR4      4       R#  L L~  \         d     Li ; i  \         d"   p\        P%                  RT4        Rp?R# Rp?ii ; i5i)z6Handle inline keyboard button clicks (update prompts).Nzupdate_prompt:r  zSent 'z' to the update process.r@   yYesNou   ⚕ Update prompt answered: **)r:   r  r  r   z.update_responsez.tmpz/Telegram update prompt answered '%s' by user %sidunknownz1Failed to write update response from callback: %s)callback_querydata
startswithr   answerr  r   r  r   r   r   with_suffix
write_textreplacer   r   r\   	from_userr   )rr   r  r  queryr  r  labelr   homeresponse_pathtmpexcs   &&&         r   rK  &TelegramAdapter._handle_callback_query  s_     %%EJJJzz/00C#A&ll&0H IlJJJ3D	))4UG1=$--! *   
	S8"$D #55M++F3CNN6"KK&KKIy IK' 	K
  		  	SLLLcRR	Ssw   &E=$E=4E=D9E=)D= <D;=D= A5E 7E=;D= =EE=
EE=E:E5/E=5E::E=c                   < V ^8  d   QhRS[ RS[ RS[S[ ,          RS[S[ ,          RS[S[S[ S[3,          ,          RS[/# )r/   r   
audio_pathcaptionrv  r  r0   r  )r3   rL   s   "r   r4   rM     sd     /T /T/T /T #	/T
 3-/T 4S>*/T 
/Tr   c                p  <"   V P                   '       g   \        RRR7      #  ^ RIpVP                  P	                  V4      '       g   \        RRV 2R7      # \        VR4      ;_uu_ 4       pVP                  R4      '       g   VP                  R4      '       d   V'       d   VP                  R	4      MRp	V P                   P                  \        V4      TV'       d
   VR
,          MRV'       d   \        V4      MRV	'       d   \        V	4      MRR7      G Rj  xL
 p
MV'       d   VP                  R	4      MRpV P                   P                  \        V4      TV'       d
   VR
,          MRV'       d   \        V4      MRV'       d   \        V4      MRR7      G Rj  xL
 p
RRR4       \        R\        X
P                  4      R7      #  L L.  + '       g   i     L4; i  \         dG   p\        P                  RT P                   TRR7       \"        ST `!  YY44      G Rj  xL 
 u Rp?# Rp?ii ; i5i)z<Send audio as a native Telegram voice message or audio file.Fr  r  NzAudio file not found: rb.oggz.opusr   Ni   N)r   voicer  r  r   )r   audior  r  r   Tr  zJ[%s] Failed to send Telegram voice/audio, falling back to base adapter: %sr   )rX   r%   r_   rQ  r   r   endswithrp   
send_voicer   
send_audior<   r  r   r   r   r   rT   )rr   r   r  r  rv  r  r   r_   
audio_file_voice_threadr  _audio_threadr   rs   s   &&&&&&,      r   r  TelegramAdapter.send_voice  s     yyye?CC"	T77>>*--!%9OPZ|7\]]j$'':&&v..*2E2Eg2N2NAIHLL$=tM $		 4 4 #G(29t=ECM4@M#m*<SW !5 ! C BJHLL$=tM $		 4 4 #G(29t=ECM4@M#m*<SW !5 ! C (* ds3>>7JKK# (',  	TLL\			   +GSSSS	Ts    H6$G" 	G" H6G" -.GG$AG1GGGG(AG5G	GGG#'G" 
H6GGG	G" "H3-6H.#H&$H.(H3)H6.H33H6c                   < V ^8  d   QhRS[ RS[ RS[S[ ,          RS[S[ ,          RS[S[S[ S[3,          ,          RS[/# )r/   r   
image_pathr  rv  r  r0   r  )r3   rL   s   "r   r4   rM   G  sd     #Y #Y#Y #Y #	#Y
 3-#Y 4S>*#Y 
#Yr   c                  <"   V P                   '       g   \        RRR7      #  ^ RIpVP                  P	                  V4      '       g   \        RRV 2R7      # V'       d   VP                  R4      MRp\        VR4      ;_uu_ 4       p	V P                   P                  \        V4      T	V'       d
   VR,          MRV'       d   \        V4      MRV'       d   \        V4      MRR	7      G Rj  xL
 p
RRR4       \        R
\        X
P                  4      R7      #  L,  + '       g   i     L2; i  \         dG   p\        P                  RT P                  TR
R7       \        ST `A  YY44      G Rj  xL 
 u Rp?# Rp?ii ; i5i)z5Send a local image file natively as a Telegram photo.Fr  r  NzImage file not found: r   r  r  r   photor  r  r   Tr  zJ[%s] Failed to send Telegram local image, falling back to base adapter: %sr   )rX   r%   r_   rQ  r   rp   r   
send_photor   r<   r  r   r   r   r   rT   send_image_file)rr   r   r  r  rv  r  r   r_   _thread
image_filer  r   rs   s   &&&&&&,     r   r  TelegramAdapter.send_image_fileG  s2     yyye?CC	Y77>>*--!%9OPZ|7\]]3;hll;/Gj$'': II00L$.5GEN49AHt6=c'l4 1   ( ds3>>7JKK ('  	YLL\			   0gXXXX	Ys    F$D. 	D. FD. !'D. :DDD,D-D1'D. FDD+	&D. .E?96E:/E20E:4E?5F:E??Fc                   < V ^8  d   QhRS[ RS[ RS[S[ ,          RS[S[ ,          RS[S[ ,          RS[S[S[ S[3,          ,          RS[/# )r/   r   	file_pathr  	file_namerv  r  r0   r  )r3   rL   s   "r   r4   rM   l  ss     !a !a!a !a #	!a
 C=!a 3-!a 4S>*!a 
!ar   c                N  <"   V P                   '       g   \        RRR7      #  \        P                  P	                  V4      '       g   \        RRV 2R7      # T;'       g     \        P                  P                  V4      pV'       d   VP                  R4      MRp	\        VR4      ;_uu_ 4       p
V P                   P                  \        V4      T
TV'       d
   VR,          MRV'       d   \        V4      MRV	'       d   \        V	4      MRR	7      G Rj  xL
 pRRR4       \        R
\        XP                  4      R7      #  L,  + '       g   i     L2; i  \         d@   p\        RT P                   RT 24       \        ST `!  YY4T4      G Rj  xL 
 u Rp?# Rp?ii ; i5i)z<Send a document/file natively as a Telegram file attachment.Fr  r  zFile not found: r   Nr  r  )r   documentfilenamer  r  r   Tr  [z] Failed to send document: )rX   r%   r_   rQ  r   basenamerp   r   send_documentr   r<   r  r   printr   rT   )rr   r   r  r  r  rv  r  r   display_namer  r   r  r   rs   s   &&&&&&&,     r   r  TelegramAdapter.send_documentl  sG     yyye?CC	a77>>),,!%9I)7UVV$CC(8(8(CL3;hll;/Gi&&! II33L).5GEN49AHt6=c'l4 4   ' ds3>>7JKK '&  	aAdii[ ;A3?@.w7W_````	as    F%$E 	E F%E "'E 
'E 1;E-EEEE'E F%EE	E F"#/FFFF"F%F""F%c                   < V ^8  d   QhRS[ RS[ RS[S[ ,          RS[S[ ,          RS[S[S[ S[3,          ,          RS[/# )r/   r   
video_pathr  rv  r  r0   r  )r3   rL   s   "r   r4   rM     sd     T TT T #	T
 3-T 4S>*T 
Tr   c                  <"   V P                   '       g   \        RRR7      #  \        P                  P	                  V4      '       g   \        RRV 2R7      # V'       d   VP                  R4      MRp\        VR4      ;_uu_ 4       pV P                   P                  \        V4      TV'       d
   VR,          MRV'       d   \        V4      MRV'       d   \        V4      MRR	7      G Rj  xL
 p	RRR4       \        R
\        X	P                  4      R7      #  L,  + '       g   i     L2; i  \         d?   p
\        RT P                   RT
 24       \        ST `  YY44      G Rj  xL 
 u Rp
?
# Rp
?
ii ; i5i)z2Send a video natively as a Telegram video message.Fr  r  zVideo file not found: r   Nr  r  )r   videor  r  r   Tr  r  z] Failed to send video: )rX   r%   r_   rQ  r   rp   r   
send_videor   r<   r  r   r   r   rT   )rr   r   r  r  rv  r  r   r  r   r  r   rs   s   &&&&&&,    r   r  TelegramAdapter.send_video  s&     yyye?CC	T77>>*--!%9OPZ|7\]]3;hll;/Gj$''1 II00L.5GEN49AHt6=c'l4 1   ( ds3>>7JKK ('  	TAdii[ 8<=+GSSSS	Ts    E:$D. 	D. E:D. !'D. :DDD,D-D1'D. E:DD+	&D. .E79.E2'E*(E2,E7-E:2E77E:c                   < V ^8  d   QhRS[ RS[ RS[S[ ,          RS[S[ ,          RS[S[S[ S[3,          ,          RS[/# )r/   r   	image_urlr  rv  r  r0   r  )r3   rL   s   "r   r4   rM     sd     9W 9W9W 9W #	9W
 3-9W 4S>*9W 
9Wr   c           	       <"   V P                   '       g   \        RRR7      #  V'       d   VP                  R4      MRpV P                   P                  \	        V4      TV'       d
   VR,          MRV'       d   \	        V4      MRV'       d   \	        V4      MRR7      G Rj  xL
 p\        R\        VP                  4      R	7      #  L$  \         Ed   p\        P                  R
T P                  TRR7        ^ RIp	T	P                  RR7      ;_uu_4       GRj  xL 
 p
T
P                  T4      G Rj  xL 
 pTP                  4        TP                  pRRR4      GRj  xL 
  M  + GRj  xL 
 '       g   i     M; iT P                   P                  \	        T4      XT'       d
   TR,          MRT'       d   \	        T4      MRR7      G Rj  xL 
 p\        R\        TP                  4      R	7      u Rp?#   \         dL   p\        P                  RT P                  TRR7       \         ST `E  YY44      G Rj  xL 
 u Rp?u Rp?# Rp?ii ; iRp?ii ; i5i)zSend an image natively as a Telegram photo.

Tries URL-based send first (fast, works for <5MB images).
Falls back to downloading and uploading as file (supports up to 10MB).
Fr  r  r   Nr  r  Tr  z8[%s] URL-based send_photo failed, trying file upload: %sr   g      >@)timeout)r   r  r  r  z+[%s] File upload send_photo also failed: %s)rX   r%   rp   r  r   r<   r  r   r   r   r   httpxAsyncClientraise_for_statusr~  r   rT   
send_image)rr   r   r
  r  rv  r  _photo_threadr  r   r  clientresp
image_datae2rs   s   &&&&&&        r   r  TelegramAdapter.send_image  s     yyye?CC)	W9AHLL5tM		,,G*1t5=CM48E#m"44 -  C ds3>>7JKK  	WNNJ			  W ,,T,:::f!'I!666D))+!%J ;:::::
 !II00L$.5GEN49AHt	 1    "$3s~~;NOO WAII!	   #W/GVVVVVW-	Ws    I C	 AC	 9C	 C	 "C##C	 I C	 	I#I9"G?D
G? E)5D8
6!E)G?"E%#G?)F/E20
F;F=AG??G?G$G?9I:I ?I
6I IIII
II IIII c                   < V ^8  d   QhRS[ RS[ RS[S[ ,          RS[S[ ,          RS[S[S[ S[3,          ,          RS[/# )r/   r   animation_urlr  rv  r  r0   r  )r3   rL   s   "r   r4   rM     sd     T TT T #	T
 3-T 4S>*T 
Tr   c           	     @  "   V P                   '       g   \        RRR7      #  V'       d   VP                  R4      MRpV P                   P                  \	        V4      TV'       d
   VR,          MRV'       d   \	        V4      MRV'       d   \	        V4      MRR7      G Rj  xL
 p\        R\        VP                  4      R	7      #  L$  \         dI   p\        P                  R
T P                  TRR7       T P                  YY44      G Rj  xL 
 u Rp?# Rp?ii ; i5i)zJSend an animated GIF natively as a Telegram animation (auto-plays inline).Fr  r  r   Nr  )r   	animationr  r  r   Tr  zA[%s] Failed to send Telegram animation, falling back to photo: %sr   )rX   r%   rp   send_animationr   r<   r  r   r   r   r   r  )	rr   r   r  r  rv  r  _anim_threadr  r   s	   &&&&&&   r   r  TelegramAdapter.send_animation  s      yyye?CC	T8@8<<4dL		00G'*1t5=CM47C#l"3 1  C ds3>>7JKK  	TLLS			   SSSS	Tsd    DC AC 8C C !C"#C DC D8DDDDDDDc                P   < V ^8  d   QhRS[ RS[S[S[ S[3,          ,          RR/# )r/   r   r  r0   Nr<   r   r   r   )r3   rL   s   "r   r4   rM   	  s0       c3h8P \` r   c                n  "   V P                   '       da    V'       d   VP                  R4      MRpV P                   P                  \        V4      RV'       d   \        V4      MRR7      G Rj  xL
  R# R#  L  \         d/   p\
        P                  RT P                  TRR7        Rp?R# Rp?ii ; i5i)zSend typing indicator.r   Ntyping)r   actionr   z1[%s] Failed to send Telegram typing indicator: %sTr   )rX   rp   send_chat_actionr   r   r   debugr   )rr   r   r  _typing_threadr   s   &&&  r   send_typingTelegramAdapter.send_typing	  s     999>Fk!:Dii00L#=Kc.&9QU 1    
  GII!	   sF   B5A9 AA9 .A7/A9 3B57A9 9B2#B-'B5-B22B5c                <   < V ^8  d   QhRS[ RS[S[ S[3,          /# )r/   r   r0   )r<   r   r   )r3   rL   s   "r   r4   rM     s'      I  I3  I4S>  Ir   c                  "   V P                   '       g   RRRR/#  V P                   P                  \        V4      4      G Rj  xL
 pRpVP                  \        P
                  8X  d   RpMWVP                  \        P                  8X  d   RpVP                  '       d   RpM!VP                  \        P                  8X  d   RpRVP                  ;'       g     VP                  ;'       g    \        V4      RVR	VP                  R
\        VR
R4      /#  L  \         dI   p\        P!                  RT P"                  TTRR7       R\        T4      RRR\        T4      /u Rp?# Rp?ii ; i5i)z&Get information about a Telegram chat.r   UnknowntypedmNgroupforumchannelusernameis_forumFz0[%s] Failed to get Telegram chat info for %s: %sTr   r   )rX   get_chatr   r+  r   GROUP
SUPERGROUPr1  CHANNELtitle	full_namer<   r0  r\   r   r   r   r   )rr   r   chat	chat_typer   s   &&   r   get_chat_infoTelegramAdapter.get_chat_info  s7    yyyIvt44	I++CL99DIyyHNN*#	h111#	=== 'Ih...%	 

DDdnnDDG	DMMGD*e<	  :$  	ILLB		   CL&$QHH	IsY   E+'D DAD 7D D +'D E+D E( =E#E(E+#E((E+c                &   < V ^8  d   QhRS[ RS[ /# )r/   r~  r0   r;   )r3   rL   s   "r   r4   rM   >  s     [ [c [c [r   c                2  aaa V'       g   V# / o^ .oR VV3R lloTpV3R lp\         P                  ! RVV4      p\         P                  ! RV3R lV4      pV3R lp\         P                  ! RWB4      pV3R	 lp\         P                  ! R
WR\         P                  R7      p\         P                  ! RV3R lV4      p\         P                  ! RV3R lV4      p\         P                  ! RV3R lV4      p\         P                  ! RV3R lV4      p\         P                  ! RV3R lV\         P                  R7      p\        V4      p\	        \        SP                  4       4      4       F  pVP                  VSV,          4      pK  	  \         P                  ! RV4      p. p\        V4       FR  w  rV	^,          ^8X  d   VP                  V
4       K&  V
3R lpVP                  \         P                  ! RW4      4       KT  	  RP                  V4      pV# )a6  
Convert standard markdown to Telegram MarkdownV2 format.

Protected regions (code blocks, inline code) are extracted first so
their contents are never modified.  Standard markdown constructs
(headers, bold, italic, links) are translated to MarkdownV2 syntax,
and all remaining special characters are escaped.
c                0    V ^8  d   QhR\         R\         /# )r/   r4  r0   r;   )r3   s   "r   r4   4TelegramAdapter.format_message.<locals>.__annotate__M  s     	 	s 	s 	r   c                V   < RS^ ,           R2pS^ ;;,          ^,          uu&   V SV&   V# )z@Stash *value* behind a placeholder token that survives escaping.z PH r   )r4  keycounterplaceholderss   & r   _ph+TelegramAdapter.format_message.<locals>._phM  s1    71:,d+CAJ!OJ %LJr   c                    < V P                  ^ 4      pRVR,          9   d   VP                  R4      ^,           M^pVRV pWR pVRR	 pVP                  RR4      P                  RR4      pS! W5,           R,           4      # )
    
:   NNN\\\`z\`z```)r-  indexr  )mrawopen_endopeningbody_and_closebodyrE  s   &     r   _protect_fenced7TelegramAdapter.format_message.<locals>._protect_fencedX  s}    ''!*C.2c"gosyy*1H)8nG ^N!#2&D<<f-55c5ADw~-..r   z(```(?:[^\n]*\n)?[\s\S]*?```)z	(`[^`]+`)c                 R   < S! V P                  ^ 4      P                  RR4      4      # )rH  rK  rL  )r-  r  rP  rE  s   &r   <lambda>0TelegramAdapter.format_message.<locals>.<lambda>l  s    c!''!*,,T6:;r   c                    < \        V P                  ^4      4      pV P                  ^4      P                  RR4      P                  RR4      pS! RV RV R24      # )   rK  rL  r  z\)r  ]()rA   r-  r  )rP  displayurlrE  s   &  r   _convert_link5TelegramAdapter.format_message.<locals>._convert_linkr  sV    "1771:.G''!*$$T62::3FC7)2cU!,--r   z\[([^\]]+)\]\(([^)]+)\)c                    < V P                  ^4      P                  4       p\        P                  ! RRV4      pS! R\	        V4       R24      # )r]  \*\*(.+?)\*\*rD   r  )r-  rO  rE   r?   rA   )rP  innerrE  s   & r   _convert_header7TelegramAdapter.format_message.<locals>._convert_headerz  sF    GGAJ$$&EFF+UE:E<./q122r   z^#{1,6}\s+(.+)$)flagsrd  c                 L   < S! R \        V P                  ^4      4       R 24      # )r  rA   r-  rY  s   &r   rZ  r[    !    cAl1771:67q9:r   z\*([^*\n]+)\*c                 L   < S! R \        V P                  ^4      4       R 24      # )_rj  rY  s   &r   rZ  r[    rk  r   z	~~(.+?)~~c                 L   < S! R \        V P                  ^4      4       R 24      # )~rj  rY  s   &r   rZ  r[    rk  r   z\|\|(.+?)\|\|c                 L   < S! R \        V P                  ^4      4       R 24      # )z||rj  rY  s   &r   rZ  r[    s!    cB|AGGAJ78;<r   z^(>{1,3}) (.+)$c                 ~   < S! V P                  ^4      R,           \        V P                  ^4      4      ,           4      # )r]   )r-  rA   rY  s   &r   rZ  r[    s)    c!''!*s*\!''!*-EEFr   z(```[\s\S]*?```|`[^`]+`)c                 (   V P                  4       pV P                  ^ 4      pV^ 8  d   W^,
          ,          R8X  d   V# VR8X  d   V^ 8  d   W^,
          ,          R8X  d   V# VR8X  d   VRV pRV9   g   RV9   d   ^ p\        V^,
          \        VR,
          R	4      R	4       Fc  pW,          R8X  d<   V^,          pV^ 8  d*   V^ 8  d   W^,
          ,          R8X  d   Vu #  RV,           # KK  W,          R8X  g   KZ  V^,          pKe  	  RV,           # )
rH  rK  (]r  Nz](httpr^  i  )rN  r-  rL  max)rP  _segschbeforedepthjs   &&     r   	_esc_bare1TelegramAdapter.format_message.<locals>._esc_bare  s    	AB1u!e!4!	SyQUtE{c/A!	Sy!%bq#v-$%E%*1q5#a$h2CR%H#'7c>$)QJE',qy+,q5Ta%[C5G35I(-  "9$ (1 &*W^$)QJE &I  "9$r   z[(){}]r  )rE   r?   	MULTILINErA   reversedrv   keysr  r   r  r  r   )rr   r~  r:   rV  ra  rf  rB  _code_split_safe_parts_idxrx  r~  rE  rC  rD  s   &&          @@@r   r  TelegramAdapter.format_message>  s    N#	 	 	/ vv,
 vv;
	.
 vv0-F	3 vvR\\

 vv:
 vv:
 vv:
 vv<
 vvF,,	
 D! D!2!2!456C<<\#%67D 7 hh:DA#K0JDax1}""4( '+ %2 ""266)Y#EF? 1@ ww{#r   c                    < V ^8  d   QhRS[ /# r.   r1   )r3   rL   s   "r   r4   rM     s     d d4 dr   c                   V P                   P                  P                  R4      pVe5   \        V\        4      '       d   VP                  4       R9   # \        V4      # \        P                  ! RR4      P                  4       R9   # )zBReturn whether group chats should require an explicit bot trigger.require_mentionTELEGRAM_REQUIRE_MENTIONfalse)true1yeson)	rK   ro   rp   r   r<   r   r2   r_   r`   r   s   & r   _telegram_require_mention)TelegramAdapter._telegram_require_mention  sq    [[&&**+<=
!*c**!'')-GGG
##yy3W=CCEIcccr   c                0   < V ^8  d   QhRS[ S[,          /# r.   )setr<   )r3   rL   s   "r   r4   rM     s     N Ns3x Nr   c                   V P                   P                  P                  R 4      pVf   \        P                  ! RR4      p\        V\        4      '       dK   V Uu0 uF=  p\        V4      P                  4       '       g   K$  \        V4      P                  4       kK?  	  up# \        V4      P                  R4       Uu0 uF*  q"P                  4       '       g   K  VP                  4       kK,  	  up# u upi u upi )free_response_chatsTELEGRAM_FREE_RESPONSE_CHATSr  ry   )
rK   ro   rp   r_   r`   r   rv   r<   rO  r   )rr   rQ  parts   &  r   _telegram_free_response_chats-TelegramAdapter._telegram_free_response_chats  s    kk##$9:;)):B?Cc4  25K#$T9J%CIOO%#KK),S)<M)<



)<MM LMs   !C0C0=C5C5c                D   < V ^8  d   QhRS[ S[P                  ,          /# r.   )r   rE   Pattern)r3   rL   s   "r   r4   rM     s     $ $4

+; $r   c                   V P                   P                  P                  R4      pVfG   \        P                  ! RR4      P                  4       pV'       d    \        P                  ! V4      pTpVf   . # \        V\        4      '       d   V.p\        V\        4      '       g7   \        P                  RV P                   \#        V4      P$                  4       . # . pV Ff  p\        V\        4      '       d   VP                  4       '       g   K1   VP'                  \(        P*                  ! V\(        P,                  4      4       Kh  	  V'       d+   \        P1                  RV P                   \3        V4      4       V#   \         d    TP                  4        Uu. uF*  qDP                  4       '       g   K  TP                  4       NK,  	  Mu upi ppT'       gL   TP                  R4       Uu. uF*  qDP                  4       '       g   K  TP                  4       NK,  	  Mu upi pp ELi ; i  \(        P.                   d.   p\        P                  RT P                   Yg4        Rp?EK  Rp?ii ; i)	z=Compile optional regex wake-word patterns for group triggers.mention_patternsNTELEGRAM_MENTION_PATTERNSr  ry   z?[%s] telegram mention_patterns must be a list or string; got %sz,[%s] Invalid Telegram mention pattern %r: %sz*[%s] Loaded %d Telegram mention pattern(s))rK   ro   rp   r_   r`   rO  jsonloadsr   
splitlinesr   r   r<   rv   r   r   r   r+  r   r  rE   compile
IGNORECASEr   r   r  )rr   patternsrQ  loadedr  compiledpatternr  s   &       r   rZ   )TelegramAdapter._compile_mention_patterns  s   ;;$$(();<))7<BBDC[!ZZ_F
 "Ih$$ zH(D))NNQ		X''
 I%'Ggs++7==??h

7BMM BC	   KKDdiiQTU]Q^_9 ! [7:~~7GX7Gt::<ldjjl7GXFX!;>99S>!Z>4ZZ\,$**,>!Z!Z[0 88 hMtyyZagghsN   E= 4H,=H)G6G
#H)-H	HH)(H),I.!I))I.c                &   < V ^8  d   QhRS[ RS[/# r/   r   r0   r   r2   )r3   rL   s   "r   r4   rM     s     4 4g 4$ 4r   c                    \        VR R4      pV'       g   R# \        \        VRR4      4      P                  R4      R,          P                  4       pVR9   # )r8  NFr+  r  r  rv  )r-  
supergroup)r\   r<   r   r   )rr   r   r8  r9  s   &&  r   _is_group_chatTelegramAdapter._is_group_chat  sN    w-fb1288=bAGGI	333r   c                &   < V ^8  d   QhRS[ RS[/# r  r  )r3   rL   s   "r   r4   rM     s     f f fD fr   c                    V P                   '       d   \        VR R4      '       g   R# \        VP                  RR4      p\        T;'       d&    \        VRR4      \        V P                   RR4      8H  4      # )reply_to_messageNFr  r  )rX   r\   r  r2   )rr   r   
reply_users   && r   _is_reply_to_bot TelegramAdapter._is_reply_to_bot  sa    yyy1CT J JW55{DI
Jdd7:tT#BgdiiY]_cFd#deer   c                &   < V ^8  d   QhRS[ RS[/# r  r  )r3   rL   s   "r   r4   rM   !  s      W  r   c           	     @  a V P                   '       g   R # \        V P                   RR4      ;'       g    RP                  R4      P                  4       p\        V P                   RR4      pV3R lpV! 4        EF!  w  rVV'       d   RV 2VP                  4       9   d    R# V F  p\	        \        VRR4      4      P                  R	4      R,          P                  4       pVR
8X  dy   V'       dq   \        \        VRR4      4      p	\        \        VR^ 4      4      p
V	^ 8  g   V
^ 8:  d   K  WYW,            P                  4       P                  4       RV 28X  d     R# K  VR8X  g   K  \        VRR4      pV'       g   K  \        VRR4      V8X  g   K    R# 	  EK$  	  R # )Fr0  Nr  @r  c               3      <"   \        S R R4      ;'       g    R\        S RR4      ;'       g    . 3x  \        S RR4      ;'       g    R\        S RR4      ;'       g    . 3x  R# 5i)r:   Nr  entitiesr  caption_entities)r\   )r   s   r   _iter_sources<TelegramAdapter._message_mentions_bot.<locals>._iter_sources(  se     '64066BUY8Z8`8`^```'9d399r77L^`d;e;k;kikkks   *A&A&A&A&Tr+  r  mentionoffsetlengthtext_mentionuserrv  )rX   r\   lstripr   r<   r   r   rO  )rr   r   bot_usernamebot_idr  source_textr  entityentity_typer  r  r  s   &f          r   _message_mentions_bot%TelegramAdapter._message_mentions_bot!  s`   yyy		:t<BBJJ3OUUWD$/	l &3_!K!L> 2k6G6G6I I"!'&&""=>DDSI"MSSU)+ 2!>?F 1!=>FzVq[ "&/:@@BHHJPQR^Q_N``# a N2"6648DtdD 9V C# # &5  r   c                &   < V ^8  d   QhRS[ RS[/# r  r  )r3   rL   s   "r   r4   rM   >  s     	 	 	T 	r   c                    V P                   '       g   R # \        VRR4      \        VRR4      3 F;  pV'       g   K  V P                    F  pVP                  V4      '       g   K    R# 	  K=  	  R # )Fr:   Nr  T)r[   r\   search)rr   r   	candidater  s   &&  r   !_message_matches_mention_patterns1TelegramAdapter._message_matches_mention_patterns>  sa    %%%!'648''9VZ:[\I11>>),, 2 ] r   c                F   < V ^8  d   QhRS[ S[,          RS[ S[,          /# r9   )r   r<   )r3   rL   s   "r   r4   rM   I  s#      HSM hsm r   c                4   V'       d0   V P                   '       d   \        V P                   R R4      '       g   V# \        P                  ! V P                   P                  4      p\        P
                  ! RV R2RV4      P                  4       pT;'       g    T# )r0  Nz(?i)@z\b[,:\-]*\s*r  )rX   r\   rE   escaper0  r?   rO  )rr   r:   r0  rF   s   &&  r   _clean_bot_trigger_text'TelegramAdapter._clean_bot_trigger_textI  sl    4999GDIIz4,P,PK99TYY//0&&E(<8"dCIIK$r   
is_commandFc                ,   < V ^8  d   QhRS[ RS[RS[/# )r/   r   r  r0   r  )r3   rL   s   "r   r4   rM   P  s#     ? ?w ?t ?X\ ?r   c          	     j   V P                  V4      '       g   R# \        \        \        VRR4      RR4      4      V P                  4       9   d   R# V P	                  4       '       g   R# V'       d   R# V P                  V4      '       d   R# V P                  V4      '       d   R# V P                  V4      # )aa  Apply Telegram group trigger rules.

DMs remain unrestricted. Group/supergroup messages are accepted when:
- the chat is explicitly allowlisted in ``free_response_chats``
- ``require_mention`` is disabled
- the message is a command
- the message replies to the bot
- the bot is @mentioned
- the text/caption matches a configured regex wake-word pattern
Tr8  Nr  r  )r  r<   r\   r  r  r  r  r  )rr   r   r  s   &&$r   _should_process_message'TelegramAdapter._should_process_messageP  s     ""7++www5tR@ATEgEgEii--//  ))%%g..55g>>r   c                >   < V ^8  d   QhRS[ RS[P                  RR/# r/   r  r  r0   Nr   r   r   )r3   rL   s   "r   r4   rM   i  s)     ( ( (,B[B[ (`d (r   c                j  "   VP                   '       d   VP                   P                  '       g   R# V P                  VP                   4      '       g   R# V P                  VP                   \        P
                  4      pV P                  VP                  4      Vn        V P                  V4       R# 5i)zHandle incoming text messages.

Telegram clients split long messages into multiple updates.  Buffer
rapid successive text messages from the same user/chat and aggregate
them into a single MessageEvent before dispatching.
N)r   r:   r  _build_message_eventr$   r=  r  _enqueue_text_eventrr   r  r  events   &&& r   r?  $TelegramAdapter._handle_text_messagei  sz      ~~~V^^%8%8%8++FNN;;))&..+:J:JK11%**=
  's   .B3"B3AB3c                >   < V ^8  d   QhRS[ RS[P                  RR/# r  r  )r3   rL   s   "r   r4   rM   y  s)     ) )F )\=V=V )[_ )r   c                B  "   VP                   '       d   VP                   P                  '       g   R# V P                  VP                   RR7      '       g   R# V P                  VP                   \        P
                  4      pV P                  V4      G Rj  xL
  R#  L5i)z!Handle incoming command messages.NT)r  )r   r:   r  r  r$   r>  handle_messager  s   &&& r   r@  TelegramAdapter._handle_commandy  sm     ~~~V^^%8%8%8++FNNt+LL))&..+:M:MN!!%(((s   .B$BA BBBc                >   < V ^8  d   QhRS[ RS[P                  RR/# r  r  )r3   rL   s   "r   r4   rM     s)     #) #)V #)lF_F_ #)dh #)r   c                J  "   VP                   '       g   R# V P                  VP                   4      '       g   R# VP                   p\        VRR4      pV'       d   \        VRR4      M\        VRR4      pV'       g   R# \        VRR4      p\        VRR4      pVe   Vf   R# R.pV'       dS   \        VRR4      p	\        VRR4      p
V	'       d   VP                  R	V	 24       V
'       d   VP                  R
V
 24       VP                  RV 24       VP                  RV 24       VP                  RV RV 24       VP                  R4       V P	                  V\
        P                  4      pRP                  V4      Vn        V P                  V4      G Rj  xL
  R#  L5i)z,Handle incoming location/venue pin messages.Nvenuelocationlatitude	longitudez![The user shared a location pin.]r6  addresszVenue: z	Address: z
latitude: zlongitude: z5Map: https://www.google.com/maps/search/?api=1&query=ry   zSAsk what they'd like to find nearby (restaurants, cafes, etc.) and any preferences.rI  )
r   r  r\   r  r  r$   rA  r   r:   r  )rr   r  r  r  r  r  latlonpartsr6  r  r  s   &&&         r   rB  (TelegramAdapter._handle_location_message  sk    ~~~++FNN;;nnWd+7<75*d3'#z[_B`h
D1hT2;#+ 55E7D1EeY5Gwug./y	23z#'({3%()LSEQRSVRWXYjk))#{/C/CDYYu%
!!%(((s*   5F#AF#=0F#.=F#,B.F#F!F#c                &   < V ^8  d   QhRS[ RS[/# )r/   r  r0   )r#   r<   )r3   rL   s   "r   r4   rM     s     
 
\ 
c 
r   c                    ^ RI Hp V! VP                  V P                  P                  P                  RR4      V P                  P                  P                  RR4      R7      # )z-Session-scoped key for text message batching.build_session_keygroup_sessions_per_userTthread_sessions_per_userFr  r  )gateway.sessionr  sourcerK   ro   rp   )rr   r  r  s   && r   _text_batch_keyTelegramAdapter._text_batch_key  sQ    5 LL$(KK$5$5$9$9:SUY$Z%)[[%6%6%:%:;UW\%]
 	
r   c                $   < V ^8  d   QhRS[ RR/# )r/   r  r0   N)r#   )r3   rL   s   "r   r4   rM     s     
 
 
$ 
r   c                   V P                  V4      pV P                  P                  V4      pVf   WP                  V&   MVP                  '       d?   VP                  '       d   VP                   RVP                   2MVP                  Vn        VP                  '       dK   VP                  P                  VP                  4       VP                  P                  VP                  4       V P                  P                  V4      pV'       d'   VP                  4       '       g   VP                  4        \        P                  ! V P                  V4      4      V P                  V&   R# )a
  Buffer a text event and reset the flush timer.

When Telegram splits a long user message into multiple updates,
they arrive within a few hundred milliseconds.  This method
concatenates them and waits for a short quiet period before
dispatching the combined message.
NrI  )r  rg   rp   r:   
media_urlsextendmedia_typesrh   r%  rm  r   r&  _flush_text_batch)rr   r  rB  rY  
prior_tasks   &&   r   r  #TelegramAdapter._enqueue_text_event  s    ""5)--11#6.3&&s+ zzzDLMMM8==/EJJ< @W\WaWa##**5+;+;<$$++E,=,=> 3377<
joo//.5.A.A""3'/
&&s+r   c                $   < V ^8  d   QhRS[ RR/# )r/   rB  r0   Nr;   )r3   rL   s   "r   r4   rM     s     > >3 >4 >r   c                  "   \         P                  ! 4       p \         P                  ! V P                  4      G Rj  xL
  V P                  P                  VR4      pV'       gA    V P                  P                  V4      VJ d   V P                  P                  VR4       R# R# \        P                  RT\        VP                  ;'       g    R4      4       V P                  V4      G Rj  xL
  V P                  P                  V4      VJ d   V P                  P                  VR4       R# R#  L LE  T P                  P                  T4      TJ d   T P                  P                  TR4       i i ; i5i)z<Wait for the quiet period then dispatch the aggregated text.Nz,[Telegram] Flushing text batch %s (%d chars)r  )r   current_taskr   rf   rg   poprh   rp   r   r   r  r:   r  )rr   rB  r  r  s   &&  r   r  !TelegramAdapter._flush_text_batch  s8    ++-	>-- > >???..223=E --11#6,F..223= G KK>S))r* %%e,,,--11#6,F..223= G @ ---11#6,F..223= GsP   E6#D5 D1'D5 &?E6%(D5 D5 -D3.D5 2?E61D5 3D5 5>E33E6c                ,   < V ^8  d   QhRS[ RS[RS[/# )r/   r  r  r0   )r#   r   r<   )r3   rL   s   "r   r4   rM     s"     , ,l , ,S ,r   c                
   ^ RI Hp V! VP                  V P                  P                  P                  RR4      V P                  P                  P                  RR4      R7      p\        VRR4      pV'       d   V R	V 2# V R
2# )z1Return a batching key for Telegram photos/albums.r  r  Tr  Fr  media_group_idNz:album:z:photo-burst)r  r  r  rK   ro   rp   r\   )rr   r  r  r  r  r  s   &&&   r   _photo_batch_key TelegramAdapter._photo_batch_key  s    5'LL$(KK$5$5$9$9:SUY$Z%)[[%6%6%:%:;UW\%]

 !&6=!]'.)9::l++r   c                $   < V ^8  d   QhRS[ RR/# )r/   	batch_keyr0   Nr;   )r3   rL   s   "r   r4   rM     s     E E# E$ Er   c                  "   \         P                  ! 4       p \         P                  ! V P                  4      G Rj  xL
  V P                  P                  VR4      pV'       gA    V P                  P                  V4      VJ d   V P                  P                  VR4       R# R# \        P                  RV\        VP                  4      4       V P                  V4      G Rj  xL
  V P                  P                  V4      VJ d   V P                  P                  VR4       R# R#  L LE  T P                  P                  T4      TJ d   T P                  P                  TR4       i i ; i5i)z;Send a buffered photo burst/album as a single MessageEvent.Nz3[Telegram] Flushing photo batch %s with %d image(s))r   r  r   ra   rb   r	  rc   rp   r   r   r  r   r  )rr   r  r  r  s   &&  r   _flush_photo_batch"TelegramAdapter._flush_photo_batch  s0    ++-		E-- ? ?@@@//33ItDE ..229=M//33ItD N KKMyZ]^c^n^nZop%%e,,,..229=M//33ItD N A
 -..229=M//33ItD NsJ   E,#D+ D''D+ &?E,%>D+ #D)$D+ (?E,'D+ )D+ +>E))E,c                *   < V ^8  d   QhRS[ RS[RR/# )r/   r  r  r0   Nr<   r#   )r3   rL   s   "r   r4   rM     s'     m mc m, m4 mr   c                   V P                   P                  V4      pVf   W P                   V&   MVP                  P                  VP                  4       VP                  P                  VP                  4       VP
                  '       dn   VP
                  '       g   VP
                  Vn        MIVP
                  VP
                  9  d/   VP
                   RVP
                   2P                  4       Vn        V P                  P                  V4      pV'       d'   VP                  4       '       g   VP                  4        \        P                  ! V P                  V4      4      V P                  V&   R# )z;Merge photo events into a pending batch and schedule flush.N

)rb   rp   r   r  r  r:   rO  rc   r%  rm  r   r&  r  )rr   r  r  rY  r  s   &&&  r   _enqueue_photo_event$TelegramAdapter._enqueue_photo_event  s   ..229=5:''	2&&u'7'78  ''(9(9:zzz}}}$)JJHMZZx}}4'/}}oT%**$F$L$L$NHM4488C
joo//5<5H5HI`I`ajIk5l''	2r   c                >   < V ^8  d   QhRS[ RS[P                  RR/# r  r  )r3   rL   s   "r   r4   rM     s.     e) e)& e)<C\C\ e)ae e)r   c                  "   VP                   '       g   R# V P                  VP                   4      '       g   R# VP                   pVP                  '       d   \        P                  pMVP
                  '       d   \        P                  pMVP                  '       d   \        P                  pMyVP                  '       d   \        P                  pMVVP                  '       d   \        P                  pM3VP                  '       d   \        P                  pM\        P                  pV P                  W44      pVP                   '       d!   V P#                  VP                   4      Vn        VP                  '       d5   V P'                  W54      G Rj  xL
  V P)                  V4      G Rj  xL
  R# VP
                  '       EdA    VP
                  R%,          pVP+                  4       G Rj  xL
 pVP-                  4       G Rj  xL
 pRp	VP.                  '       d=   R& F6  p
VP.                  P1                  4       P3                  V
4      '       g   K4  T
p	 M	  \5        \7        V4      V	R7      pV.Vn        RV	P;                  R4       2.Vn        \>        PA                  RV4       \C        VRR4      pV'       d&   V PE                  \G        V4      V4      G Rj  xL
  R# V PI                  WS4      pV PK                  W4       R# VP                  '       dz    VP                  P+                  4       G Rj  xL
 pVP-                  4       G Rj  xL
 p\Q        \7        V4      RR7      pV.Vn        R.Vn        \>        PA                  RV4       EM`VP                  '       dz    VP                  P+                  4       G Rj  xL
 pVP-                  4       G Rj  xL
 p\Q        \7        V4      RR7      pV.Vn        R.Vn        \>        PA                  RV4       EMVP                  '       Ed   VP                  p Rp	VPR                  ;'       g    RpV'       d3   \T        PV                  PY                  V4      w  pp	V	P1                  4       p	V	'       gY   VPZ                  '       dG   \\        P^                  ! 4        UUu/ uF	  w  ppVVbK  	  pppVPa                  VPZ                  R4      p	V	\\        9  d   RPc                  \e        \\        Pf                  ! 4       4      4      pRT	;'       g    R RV 2Vn        \>        PA                  RT	;'       g    R4       V P)                  V4      G Rj  xL
  R# R'pVPh                  '       d   VPh                  V8  dC   RVn        \>        PA                  RVPh                  4       V P)                  V4      G Rj  xL
  R# VP+                  4       G Rj  xL
 pVP-                  4       G Rj  xL
 p\7        V4      p\k        TT;'       g    RV	 24      p\\        V	,          pV.Vn        V.Vn        \>        PA                  RV4       R(pV	R)9   d   \m        V4      V8:  ds    VPo                  R4      pT;'       g    RV	 2p\p        Pr                  ! RRV4      pR V R!V 2pVP$                  '       d   V R"VP$                   2Vn        MVVn         \C        VRR4      pV'       d&   V PE                  \G        V4      V4      G Rj  xL
  R# V P)                  V4      G Rj  xL
  R#  EL EL EL_ ELJ ELw  \L         d$   p\>        PO                  RTR	R
7        Rp?ELxRp?ii ; i ELP EL;  \L         d#   p\>        PO                  RTR	R
7        Rp?LRp?ii ; i EL EL  \L         d#   p\>        PO                  RTR	R
7        Rp?LRp?ii ; iu uppi  EL EL# EL EL  \t         d    \>        PO                  R#R	R
7        EL8i ; i  \L         d$   p\>        PO                  R$TR	R
7        Rp?ELeRp?ii ; i EL: EL"5i)*zBHandle incoming media messages, downloading images to local cache.N.jpgextzimage/r  z"[Telegram] Cached user photo at %sr  z$[Telegram] Failed to cache photo: %sTr   r  z	audio/oggz"[Telegram] Cached user voice at %sz$[Telegram] Failed to cache voice: %sz.mp3z	audio/mp3z"[Telegram] Cached user audio at %sz$[Telegram] Failed to cache audio: %sr  r  zUnsupported document type 'r  z'. Supported types: z([Telegram] Unsupported document type: %szLThe document is too large or its size could not be verified. Maximum: 20 MB.z'[Telegram] Document too large: %s bytesr  z%[Telegram] Cached user document at %szutf-8z	[^\w.\- ]rm  z[Content of z]:
r  zJ[Telegram] Could not decode text file as UTF-8, skipping content injectionz'[Telegram] Failed to cache document: %srv  )z.png.webpz.gifz.jpegr  i  @i  )z.mdz.txt);r   r  stickerr$   STICKERr  rC  r  rD  r  rE  r  rF  r  DOCUMENTr  r  r  r:   _handle_stickerr  get_filedownload_as_bytearrayr  r   r  r&   bytesr   r  r  r   r   r\   _queue_media_group_eventr<   r  r  r   r   r'   r  r_   rQ  splitext	mime_typer)   itemsrp   r   sortedr  	file_sizer(   r  decoderE   r?   UnicodeDecodeError)rr   r  r  r  msg_typer  r  file_objimage_bytesr  r  cached_pathr  r  r   audio_bytesdocoriginal_filenamerm  kr}   mime_to_extsupported_listMAX_DOC_BYTES	doc_bytes	raw_bytesr*  MAX_TEXT_INJECT_BYTEStext_contentr  	injections   &&&                            r   rJ  %TelegramAdapter._handle_media_message  s    ~~~++FNN;;nn ;;;"**HYYY"((HYYY"((HYYY"((HYYY"((H\\\"++H"++H))#8 ;;;55ckkBEJ ;;;&&s222%%e,,, 999Y		"!&!11$,$B$B$DD%%%%O	#--335>>yII"+C! &P
 5U;5GSQ$/= '-cjjo->%?$A!@+N!(.>!E!77N8KUSSS  !% 5 5e AI--i? 999Y!$!3!3!55$,$B$B$DD4U;5GVT$/= %0M!@+N YYYY!$!3!3!55$,$B$B$DD4U;5GVT$/= %0M!@+N
 \\\,,C@\$'MM$7$7R!$WW--.?@FAs))+C s}}}4L4R4R4T"U4TDAq1a44TK"U%//#--<C 66%)YYv6N6S6S6U/V%WN5c6F6FY5G H,,:+;= J KK JCL\L\S\]--e444 !1}}}(E* J KK I3==Y--e444 "%/"*"@"@"BB	!),	7	CTChChZbcfbgXhi4S9	$/= %.K!C[Q )3%/)c)n@U.U'0'7'7'@'8'L'Lhse<L')vvlC'N&2<.\N$S	 :::,5;d5::,)GEJ)2EJ !&6=//N0CUKKK!!%(((I 3, 2D T  YEqSWXXY 6D
  YEqSWXXY 6D
  YEqSWXXY  #V 5 5 0B( . h%) '   \H!VZ[[\
 L 	)s  5a"a""a";"a""a""a"$"a"A5a"=a"]a"*]+a"&] +]
,] ]] 1] B] ]] a" "] a"^
 4^5^
 ^A ^
 a""_  ?^: _  ^=A _  a"-a":`+ 
`+ 9`+ `+ &`+ >_0A `+ .%`+ `+ /_60`+ 4a"6A `+ _9`+ a"`+ 0_<1`+ _?	`+ 'A`+ >` 7` ` &a"'` .4a""a#a"=a>a"a"
] ] ] ^]<6a"<^a"^
 ^
 
^7^2-a"2^77a":_  =_   _-_(#a"(_--a"0`+ 9`+ <`+ ?`+ "`($`+ %a"'`((`+ +a6aa"aa"a"c                *   < V ^8  d   QhRS[ RS[RR/# )r/   r  r  r0   Nr  )r3   rL   s   "r   r4   rM     s#     
 
S 
 
Z^ 
r   c                  "   V P                   P                  V4      pVf   W P                   V&   MVP                  P                  VP                  4       VP                  P                  VP                  4       VP
                  '       do   VP
                  '       dL   VP
                  VP
                  P                  R4      9  d!   VP
                   RVP
                   2Vn        MVP
                  Vn        V P                  P                  V4      pV'       d   VP                  4        \        P                  ! V P                  V4      4      V P                  V&   R# 5i)aX  Buffer Telegram media-group items so albums arrive as one logical event.

Telegram delivers albums as multiple updates with a shared media_group_id.
If we forward each item immediately, the gateway thinks the second image is a
new user message and interrupts the first. We debounce briefly and merge the
attachments into a single MessageEvent.
Nr  )rd   rp   r   r  r  r:   r   re   rm  r   r&  _flush_media_group_event)rr   r  r  rY  r  s   &&&  r   r(  (TelegramAdapter._queue_media_group_event  s     ++//?7<$$^4&&u'7'78  ''(9(9:zzz===zz)<)<V)DD+3==/ejj\(J$)JJHM,,00@
292E2E)).93
/s   B
E"E"A>E"AE"c                $   < V ^8  d   QhRS[ RR/# )r/   r  r0   Nr;   )r3   rL   s   "r   r4   rM     s     	> 	>S 	>T 	>r   c                  "    \         P                  ! V P                  4      G R j  xL
  V P                  P	                  VR 4      pVe   V P                  V4      G R j  xL
  T P                  P	                  TR 4       R #  L[ L$  \         P                   d!     T P                  P	                  TR 4       R # i ; i  T P                  P	                  TR 4       i ; i5ir{   )r   r   MEDIA_GROUP_WAIT_SECONDSrd   r	  r  CancelledErrorre   )rr   r  r  s   && r   rC  (TelegramAdapter._flush_media_group_event  s     	>-- = =>>>,,00FE ))%000 ##''= ? 1%% 	##''=	 ##''=s\   C #B B8B  B!B %C B B B<B? C ;B<<B? ?CC c                (   < V ^8  d   QhRS[ RRRR/# )r/   r  r  r#   r0   N)r   )r3   rL   s   "r   r4   rM     s'     A A A AD Ar   c                l  "   ^ RI HpHpHpHpHp VP                  pVP                  ;'       g    Rp	VP                  ;'       g    Rp
VP                  '       g   VP                  '       d   V! V	4      Vn        R# V! VP                  4      pV'       dY   V! VR,          VP                  RV	4      VP                  RV
4      4      Vn        \        P                  RVP                  4       R#  VP!                  4       G Rj  xL
 pVP#                  4       G Rj  xL
 p\%        \'        V4      RR	7      p\        P                  R
V4       ^ RIHp ^ RIpV! VVR7      G Rj  xL
 pVP/                  V4      pVP                  R4      '       d7   VP                  RR4      pV! VP                  VW4       V! VW4      Vn        R# T! V	'       d   RV	 2MRW4      Vn        R#  L L L  \0         d?   p\        P3                  RTRR7       T! T	'       d   RT	 2MRY4      Tn         Rp?R# Rp?ii ; i5i)z
Describe a Telegram sticker via vision analysis, with caching.

For static stickers (WEBP), we download, analyze with vision, and cache
the description by file_unique_id. For animated/video stickers, we inject
a placeholder noting the emoji.
)get_cached_descriptioncache_sticker_descriptionbuild_sticker_injection build_animated_sticker_injectionSTICKER_VISION_PROMPTr  Ndescriptionemojiset_namez [Telegram] Sticker cache hit: %sr   r  z"[Telegram] Analyzing sticker at %s)vision_analyze_tool)r
  user_promptr  analysisz	a stickerza sticker with emoji z%[Telegram] Sticker analysis error: %sTr   )gateway.sticker_cacherL  rM  rN  rO  rP  r!  rR  rS  is_animatedis_videor:   file_unique_idrp   r   r   r%  r&  r&   r'  tools.vision_toolsrT  r  r  r   r   )rr   r  r  rL  rM  rN  rO  rP  r!  rR  rS  cachedr1  r2  r3  rT  _jsonresult_jsonresultrQ  r   s   &&&                  r   r$  TelegramAdapter._handle_sticker  s    	
 	
 ++####))r '"2"2"29%@EJ ((>(>?0}%vzz'5'A6::jZbCcEJ KK:G<R<RS	$--//H ( > > @@K0{1CQKKK<kJ>  3%1! K [[-Fzz)$$$jj[A)'*@*@+u_4[%R
 57<+E73+
) 0@   	NNBAPTNU038'w/kEJJ	s   AH4H4H4-(H4AH4/G( G"G( G$AG( "G&#+G( 4G( H4	G( G(  H4"G( $G( &G( (H133H,&H4,H11H4c                   < V ^8  d   QhRR/# r   r   )r3   rL   s   "r   r4   rM   (  s     +Z +Zt +Zr   c                    ^ RI Hp V! 4       R,          pVP                  4       '       g   R# ^ RIp\	        VR4      ;_uu_ 4       pVP                  V4      ;'       g    / pRRR4       XP                  R/ 4      P                  R/ 4      P                  R/ 4      P                  R. 4      pV'       g   R# W`n        V F  pVP                  R	4      pV'       g   K  VP                  R
. 4       F  p	V	P                  R4      p
V	P                  R4      pV
'       g   K/  V'       g   K9  V RV 2pWP                  9  g   KR  \        V
4      V P                  V&   \        P                  RV P                  W4       K  	  K  	  R#   + '       g   i     EL*; i  \         d-   p\        P                  RT P                  T4        Rp?R# Rp?ii ; i)zRe-read dm_topics from config.yaml and load any new thread_ids into cache.

This allows topics created externally (e.g. by the agent via API) to be
recognized without a gateway restart.
r   r   Nr   r   r   ro   rS   r   r   r   r   r  z8[%s] Hot-loaded DM topic from config: %s -> thread_id=%sz/[%s] Failed to reload dm_topics from config: %s)r   r   r   r   r   r   rp   rq   rn   r   r   r   r   r   r$  )rr   r   r   r   r   rK   rS   r   cidr   tidr   r  r   s   &             r   _reload_dm_topics_from_config-TelegramAdapter._reload_dm_topics_from_config(  sr   %	Z8)+m;K%%'' k3''1+11r ( 

;+Z$Wb!["%	   &/"'
 nnY/#"5A%%,C55=Dstt'*e1TFO	$OO;9<SDOOI6"KK Z $		9 6	 ( ('':  	ZLLJDIIWXYY	ZsO   )F F F"AF 6A"F F 'F  AF F		F G"!G		Gc          	      b   < V ^8  d   QhRS[ RS[S[ ,          RS[S[S[ S[3,          ,          /# )r/   r   r   r0   r  )r3   rL   s   "r   r4   rM   U  s8     % %# %(3- %HUYZ]_bZbUcLd %r   c                   V'       g   R# \        V4      pV P                  P                  4        F  w  rEWS8X  g   K  VP                  V R24      '       g   K)  VP	                  R^4      ^,          pV P
                   F[  p\        VP                  R4      4      V8X  g   K$  VP                  R. 4       F!  pVP                  R4      V8X  g   K  Vu u u # 	  K]  	  RV/u # 	  V P                  4        V P                  P                  4        F  w  rEWS8X  g   K  VP                  V R24      '       g   K)  VP	                  R^4      ^,          pV P
                   F[  p\        VP                  R4      4      V8X  g   K$  VP                  R. 4       F!  pVP                  R4      V8X  g   K  Vu u u # 	  K]  	  RV/u # 	  R# )zLook up DM topic config by chat_id and thread_id.

Returns the topic config dict (name, skill, etc.) if this thread_id
matches a known DM topic, or None.
Nr  r   r   r   )	r   rn   r+  r  r   rq   r<   rp   re  )	rr   r   r   thread_id_intrB  
cached_tidr   r   r   s	   &&&      r   _get_dm_topic_info"TelegramAdapter._get_dm_topic_infoU  st    I  $446OC*s~~	m/L/L YYsA.q1
"&"8"8J:>>)45@!+"!=A uuV}
:'( "> #9
 
++  7 	**,  $446OC*s~~	m/L/L YYsA.q1
"&"8"8J:>>)45@!+"!=A uuV}
:'( "> #9
 
++  7 r   c                0   < V ^8  d   QhRS[ RS[ RS[ RR/# )r/   r   r   r   r0   Nr;   )r3   rL   s   "r   r4   rM   |  s+      C C UX ]a r   c                    V RV 2pW@P                   9  d<   \        V4      V P                   V&   \        P                  RV P                  WB4       R# R# )zLCache a thread_id -> topic_name mapping discovered from an incoming message.r  z5[%s] Cached DM topic from message: %s -> thread_id=%sN)rn   r   r   r   r   )rr   r   r   r   r  s   &&&& r   _cache_dm_topic_from_message,TelegramAdapter._cache_dm_topic_from_message|  sK    iq-	OO+),YDOOI&KKG		9 ,r   c                ,   < V ^8  d   QhRS[ RS[RS[/# )r/   r   r0  r0   )r   r$   r#   )r3   rL   s   "r   r4   rM     s'     I
 I
G I
{ I
| I
r   c                    VP                   pVP                  pRpVP                  \        P                  \        P
                  39   d   RpM!VP                  \        P                  8X  d   RpVP                  pV'       d   \        V4      MRpRpRp	VR8X  d   V'       d   V P                  \        VP                  4      V4      p
V
'       d#   V
P                  R4      pV
P                  R4      p	\        VR4      '       d`   VP                  '       dN   VP                  P                  pV'       d0   V P                  \        VP                  4      W{4       V'       g   TpMVR8X  d   V'       d   V P                   P"                  P                  R. 4      pV F  p\        VP                  R	R
4      4      \        VP                  4      8X  g   K8  VP                  R. 4       FN  pVP                  R4      pVf   K  \        V4      V8X  g   K,  VP                  R4      pVP                  R4      p	 M	   M	  T P%                  \        VP                  4      VP&                  ;'       g!    \        VR4      '       d   VP(                  MRTV'       d   \        VP                  4      MRV'       d   VP(                  MRVVR7      pRpRpVP*                  '       d^   \        VP*                  P,                  4      pVP*                  P.                  ;'       g!    VP*                  P0                  ;'       g    Rp\3        VP.                  ;'       g    R
VVV\        VP,                  4      VVV	VP4                  R7	      # )z-Build a MessageEvent from a Telegram message.r,  r-  r/  Nr   skillforum_topic_createdgroup_topicsr   r  r   r   r7  )r   	chat_namer9  user_id	user_namer   
chat_topic)	r:   message_typer  raw_messager  r  reply_to_text
auto_skill	timestamp)r8  r  r+  r   r3  r4  r5  r   r<   rk  r  rp   hasattrrt  r   ro  rK   ro   build_sourcer6  r7  r  r  r:   r  r#   date)rr   r   r0  r8  r  r9  thread_id_rawthread_id_strry  topic_skill
topic_infocreated_namegroup_topics_configr   r   rd  r  r  r|  s   &&&                r   r  $TelegramAdapter._build_message_event  s   ||   	99)<)<==IYY(***!I  11.;M*
00TWW}MJ'^^F3
(nnW5 w 5667;V;V;V&::??55c$''lM`%%1
'!m(,(9(9(=(=nb(Q1
z~~i45TWWE!+"!=#ii4?s3x=/H).6):J*/))G*<K! ">  2 ""Ljj\\wt[7Q7QT^^W[$(CLd(,dnn$#! # 
 ###g66AABK#4499eeW=U=U=]=]eeaeM##!7--. +'"ll

 
	
r   )rW   rX   rn   rq   ra   rd   re   r[   rc   rb   rh   rg   rk   rm   rj   rl   r]   rf   ri   rY   )NN)r  r  )NNN)NNNNr{   )>r   r   r   r   __doc__r  rG  rU   r   staticmethodr   r   r   r   r   r   r  rg  rs  r{  r  r  r  rK  r  r  r  r  r  r  r&  r:  r  r  r  rZ   r  r  r  r  r  r  r?  r@  rB  r  r  r  r  r  r  rJ  r(  rC  r$  re  rk  ro  r  r   __classdictcell____classcell__)rs   rL   s   @@r   rI   rI   o   s     "^ ^:c c 
 
 * *AG AGF6) 6)p* *X)j )jVDZ DZL\ \|%B %BN$ $(UU UUnQ; Q;f; ;>!S !SF/T /Tb#Y #YJ!a !aFT T>9W 9WvT T@ & I  ID[ [~d dN N$ $L4 4f f :	 	 ?e ? ?2( ( ) )#) #)R
 

 
:> >*, ,E Em m(e) e)N
 
:	> 	>A AF+Z +ZZ% %N I
 I
 I
r   rI   )Dr  r   r  loggingr_   rE   r!  r   r   r   r   	getLoggerr   r   r   r   r   r   r	   r
   telegram.extr   r   r   r   r<  r   r   telegram.constantsr   r   telegram.requestr   r6   r   r   syspathlibr   _PathrQ  insertr<   __file__resolveparentsgateway.configr    r!   gateway.platforms.baser"   r#   r$   r%   r&   r'   r(   r)   "gateway.platforms.telegram_networkr*   r+   r,   r7   r  r>   rA   rG   rI   r   r   r   <module>r     sB      	 	 , ,			8	$!%YY  7-.  ! 3uX..088;< = 3	 	 	  **<=.
(`!
) `!
_  %F
CGKN LGIH $L)%s   .D /D>=D>