+
    jHàj¿•  ã                  óF  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIH	t	 ^ RI
Ht ^ RIHtHtHt ^ RIHt ^ RIHt ^ RIHt ^ R	IHtHt ^ R
IHt ^ RIHt ^ RIHt ^ RIH t  ]'       d   ^ RI!H"t" ^ RI#H$t$ ]PJ                  ! R4      t&R R lt'R R lt( ! R R4      t)R# )zùTelegram forum-topic and Discord auto-thread binding/rename methods for GatewayRunner (MRO mixin).
``gateway.run`` internals are imported lazily inside method bodies (import cycle), so
``patch("gateway.run.X")`` keeps intercepting them at call time.)ÚannotationsN)Úsuppress)ÚPath)ÚTYPE_CHECKINGÚOptionalÚTuple)Ú&project_compaction_message_for_display©Út)ÚPlatform)Ú_prefix_within_utf16_limitÚ	utf16_len)ÚMessageEvent)ÚSessionSource©Úreplace_source)Úis_truthy_value)ÚGatewayRunner)Ú
TurnRunnerzgateway.runc               ó   € V ^8„  d   QhRR/# )é   ÚreturnÚtuple© )Úformats   "Ú7/home/ubuntu/.hermes/hermes-agent/gateway/run_topics.pyÚ__annotate__r       s   € ÷ Rñ R˜eñ Ró    c                 ó.   € \        R 4      \        R4      3# )zgateway.topic.restore_step_1zgateway.topic.restore_step_2r	   r   r   r   Ú_topic_restore_stepsr       s   € ÜÐ,Ó-¬qÐ1OÓ/PÐQÐQr   c               ó    € V ^8„  d   QhRRRR/# ©r   ÚtitleÚstrr   r   )r   s   "r   r   r   $   s   € ÷ ]ñ ]˜3ð ] 3ñ ]r   c                óš   € \         P                  ! R R\        T ;'       g    R4      4      P                  4       ;'       g    \	        R4      # )z\s+Ú Ú úgateway.topic.default_title)ÚreÚsubr#   Ústripr
   ©r"   s   &r   Ú_collapse_titler,   $   s7   € Ü�6Š6�&˜#œs 5§; ;¨BÓ/Ó0×6Ñ6Ó8×\Ð\¼AÐ>[Ó<\Ð\r   c                  ó  € ] tR t^(tRt]R R l4       tR t]R R l4       tR R lt	R	 R
 lt
R R ltR R ltR R ltR R ltR R ltR R ltR R ltR R ltR R ltR R ltR R  ltR! R" ltR# R$ ltR% R& ltR' R( ltR) R* ltR+ R, ltR- R. ltR/ R0 ltR1 R2 ltR3 R4 ltR5 R6 lt R7 R8 lt!R9 R: lt"R; R< lt#R= R> lt$RSR@ RA llt%RB RC lt&RD RE lt'RF RG lt(RH RI lt)RJ RK lt*RL RM lt+RN RO lt,RP RQ lt-RRt.R?# )TÚGatewayTopicThreadsMixinzVTelegram forum-topic and Discord auto-thread binding/rename methods for GatewayRunner.c               ó    € V ^8„  d   QhRRRR/# ©r   Úsourcer   r   r#   r   )r   s   "r   r   Ú%GatewayTopicThreadsMixin.__annotate__.   s   € ÷ Pñ P¨]ð P¸sñ Pr   c                ór   € \        \        V RR4      ;'       g    R4      P                  4       ;'       g    R# )zÄProfile namespace for topic-mode rows: the profile stamped on the routed event, never the
process-global one (under multiplex that mis-attributes state across bots sharing state.db).

See #76423.
ÚprofileNr&   Údefault)r#   Úgetattrr*   ©r1   s   &r   Ú_telegram_topic_profile_nameÚ5GatewayTopicThreadsMixin._telegram_topic_profile_name-   s1   € ô ”7˜6 9¨dÓ3×9Ð9°rÓ:×@Ñ@ÓB×OÐOÀiÐOr   c                óB   € \        V RR4      pVf   R# \        VRV4      # )zPThe sync SessionDB handle, or None. Only for callers that provably run off-loop.Ú_session_dbNÚ_db)r6   )ÚselfÚ
session_dbs   & r   Ú_sync_session_dbÚ)GatewayTopicThreadsMixin._sync_session_db6   s)   € ä˜T =°$Ó7ˆ
Ø!Ò)ˆtÐU¬w°zÀ5È*Ó/UÐUr   c               ó    € V ^8„  d   QhRRRR/# ©r   r1   r   r   Úboolr   )r   s   "r   r   r2   <   s   € ÷ Qñ Q ð Q°$ñ Qr   c                	ój   € V P                   \        P                  8H  ;'       d    V P                  R 8H  # )Údm)Úplatformr   ÚTELEGRAMÚ	chat_typer7   s   &r   Ú_is_telegram_dmÚ(GatewayTopicThreadsMixin._is_telegram_dm;   s*   € à�‰¤(×"3Ñ"3Ñ3×PÐP¸×8HÑ8HÈDÑ8PÐPr   c               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2   ?   s   € ÷ ñ °=ð ÀTñ r   c                óN  € V P                  V4      '       d   V P                  4       MRpVf   R#  VP                  \        VP                  4      \        VP
                  4      V P                  V4      R7      pVRJ #   \         d    \        P                  RRR7        R# i ; i)z>Return whether Telegram DM topic mode is active for this chat.NF©Úchat_idÚuser_idÚprofile_namez(Failed to read Telegram topic mode stateT©Úexc_info)
rI   r?   Úis_telegram_topic_mode_enabledr#   rN   rO   r8   Ú	ExceptionÚloggerÚdebug)r=   r1   r>   Úraws   &&  r   Ú_telegram_topic_mode_enabledÚ5GatewayTopicThreadsMixin._telegram_topic_mode_enabled?   sœ   € à04×0DÑ0DÀV×0LÒ0L�T×*Ñ*Ô,ÐRVˆ
ØÒÙð	Ø×;Ñ;Ü˜FŸN™NÓ+´S¸¿¹Ó5HØ!×>Ñ>¸vÓFð <ó ˆCð �dˆ{Ðøô ô 	Ü�L‰LÐCÈdˆLÔSÚð	ús   ±A	A> Á>"B$Â#B$c               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2   P   s   € ÷ 
ñ 
°Mð 
Àdñ 
r   c                ó¾   € V P                  V4      ;'       dF    V P                  V4      ;'       d-    \        VP                  ;'       g    R4      V P                  9   # )zUTrue for the main Telegram DM (or General topic) when topic mode has made it a lobby.r&   )rI   rX   r#   Ú	thread_idÚ_TELEGRAM_GENERAL_TOPIC_IDS©r=   r1   s   &&r   Ú_is_telegram_topic_root_lobbyÚ6GatewayTopicThreadsMixin._is_telegram_topic_root_lobbyP   s]   € ð × Ñ  Ó(÷ Pð P¨T×-NÑ-NÈvÓ-V÷ Pð PÜ�F×$Ñ$×*Ð*¨Ó+¨t×/OÑ/OÑOð	
r   c               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2   W   s   € ÷ 
ñ 
¨mð 
Àñ 
r   c                óæ   € \        VP                  ;'       g    R4      pV P                  V4      ;'       d;    V P                  V4      ;'       d"    \	        V4      ;'       d    W P
                  9  # )z9True for a user-created Telegram private-chat topic lane.r&   )r#   r\   rI   rX   rC   r]   )r=   r1   Útids   && r   Ú_is_telegram_topic_laneÚ0GatewayTopicThreadsMixin._is_telegram_topic_laneW   sq   € ä�&×"Ñ"×(Ð( bÓ)ˆà× Ñ  Ó(÷ Jð J¨T×-NÑ-NÈvÓ-V÷ Jð JÜ�S“	÷Jð JØ!×)IÑ)IÑIð	
r   c               ó    € V ^8„  d   QhRRRR/# ©r   r1   r   r   zOptional[str]r   )r   s   "r   r   r2   _   s   € ÷ ]ñ ]°=ð ]À]ñ ]r   c                ó€   € \        VP                  ;'       g    R4      pV'       d   V P                  V4       RV 2# R# )z­Cooldown key (profile, chat_id): profiles sharing a Telegram private chat_id under
multiplex must not suppress each other's lobby reminders / capability hints.

See #76423.
r&   Ú:N)r#   rN   r8   )r=   r1   rN   s   && r   Ú_telegram_topic_cooldown_keyÚ5GatewayTopicThreadsMixin._telegram_topic_cooldown_key_   s?   € ô �f—n‘n×*Ð*¨Ó+ˆßKR�$×3Ñ3°FÓ;Ð<¸A¸g¸YÐGÐ\ÐX\Ð\r   c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   r1   r   Úattrr#   Ú
cooldown_sÚfloatr   rC   r   )r   s   "r   r   r2   h   s*   € ÷ ñ °ð Àcð ÐW\ð Ðaeñ r   c                óú   € \        W4      '       g   \        W/ 4       V P                  V4      pV'       g   R# \        W4      \        P
                  ! 4       reWeP                  VR4      ,
          V8  d   R# WeV&   R# )zOPer-(profile, chat) debounce: True (and stamp now) when the window has elapsed.Tg        F)ÚhasattrÚsetattrrj   r6   ÚtimeÚ	monotonicÚget)r=   r1   rm   rn   ÚkeyÚstampsÚnows   &&&&   r   Ú_telegram_cooldown_elapsedÚ3GatewayTopicThreadsMixin._telegram_cooldown_elapsedh   sc   € ä�t×"Ò"Ü�D Ô#Ø×/Ñ/°Ó7ˆßÙÜ˜dÓ)¬4¯>ª>Ó+;�Ø—‘˜C Ó%Õ%¨
Ô2ÙØˆs‰Ùr   c               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2   u   s   € ÷ @ñ @¸=ð @ÈTñ @r   c                ó<   € V P                  VRV P                  4      # )zXRate-limit root-DM lobby reminders to one per cooldown window, not one per prompt typed.Ú_telegram_lobby_reminder_ts)ry   Ú#_TELEGRAM_LOBBY_REMINDER_COOLDOWN_Sr^   s   &&r   Ú$_should_send_telegram_lobby_reminderÚ=GatewayTopicThreadsMixin._should_send_telegram_lobby_reminderu   s   € à×.Ñ.¨vÐ7TÐVZ×V~ÑV~ÓÐr   c               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2   y   s   € ÷ Bñ B¸Mð BÈdñ Br   c                ó<   € V P                  VRV P                  4      # )z]Rate-limit the BotFather Threads Settings screenshot (repeated /topic must not re-upload it).Ú_telegram_capability_hint_ts)ry   Ú$_TELEGRAM_CAPABILITY_HINT_COOLDOWN_Sr^   s   &&r   Ú%_should_send_telegram_capability_hintÚ>GatewayTopicThreadsMixin._should_send_telegram_capability_hinty   s-   € à×.Ñ.¨vÐ7UÐW[÷  XAñ  XAó  Bð  	Br   c               ó   € V ^8„  d   QhRR/# ©r   r   r#   r   )r   s   "r   r   r2      s   € ÷ -ñ -°Cñ -r   c                	ó   € \        R 4      # )zgateway.topic.root_lobbyr	   ©r=   s   &r   Ú"_telegram_topic_root_lobby_messageÚ;GatewayTopicThreadsMixin._telegram_topic_root_lobby_message   s   € ÜÐ+Ó,Ð,r   c               ó   € V ^8„  d   QhRR/# rˆ   r   )r   s   "r   r   r2   ‚   s   € ÷ +ñ +°#ñ +r   c                	ó   € \        R 4      # )zgateway.topic.root_newr	   rŠ   s   &r   Ú _telegram_topic_root_new_messageÚ9GatewayTopicThreadsMixin._telegram_topic_root_new_message‚   s   € ÜÐ)Ó*Ð*r   c               ó    € V ^8„  d   QhRRRR/# rg   r   )r   s   "r   r   r2   …   s   € ÷ _ñ _°ð _À=ñ _r   c                	óJ   € V P                  V4      '       d   \        R 4      # R# )zgateway.topic.new_headerN)rd   r
   r^   s   &&r   Ú_telegram_topic_new_headerÚ3GatewayTopicThreadsMixin._telegram_topic_new_header…   s$   € Ø04×0LÑ0LÈV×0TÒ0TŒqÐ+Ó,Ð^ÐZ^Ð^r   c               ó   € V ^8„  d   QhRR/# rˆ   r   )r   s   "r   r   r2   ˆ   s   € ÷ 'ñ '¨3ñ 'r   c                	ó   € \        R 4      # )zgateway.topic.helpr	   rŠ   s   &r   Ú_telegram_topic_help_textÚ2GatewayTopicThreadsMixin._telegram_topic_help_textˆ   s   € ÜÐ%Ó&Ð&r   c               ó    € V ^8„  d   QhRRRR/# ©r   r1   r   r   ÚNoner   )r   s   "r   r   r2   �   s   € ÷ 	
ñ 	
°]ð 	
ÐVZñ 	
r   c           
     ót  € V P                  4       pVe%   VP                  '       d   VP                  '       g   R# TP                  \	        VP                  4      \	        VP                  4      \	        VP
                  ;'       g    R4      VP                  VP                  V P                  V4      R7       R# )zPPersist the Telegram topic -> Hermes session binding for topic lanes (off-loop).Nr&   )rN   r\   rO   Úsession_keyÚ
session_idrP   )	r?   rN   r\   Úbind_telegram_topicr#   rO   r�   rž   r8   )r=   r1   Úsession_entryr>   s   &&& r   Ú_record_telegram_topic_bindingÚ7GatewayTopicThreadsMixin._record_telegram_topic_binding�   s�   € à×*Ñ*Ó,ˆ
ØÒ V§^§^ ^¸6×;K×;KÐ;KÙØ×&Ñ&Ü˜Ÿ™Ó'´3°v×7GÑ7GÓ3HÔRUÐV\×VdÑVd×VjÐVjÐhjÓRkØ%×1Ñ1¸m×>VÑ>VØ×:Ñ:¸6ÓBð 	'ö 	
r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r1   r   Úreasonr#   r   r›   r   )r   s   "r   r   r2   ˜   s(   € ÷ ^ñ ^°=ð ^Ð\_ð ^Ðdhñ ^r   c               ó°   € V P                  V4      '       g   R#  V P                  W4       R#   \         d    \        P	                  RTRR7        R# i ; i)ab  Update the topic binding to ``session_entry.session_id``: a stale binding after a mid-turn
compression rotation reloads the oversized parent next message, retriggering compression.

Telegram topic lanes persist a (chat_id, thread_id) -> session_id row so reopening a topic in a
fresh process resumes the right Hermes session. See #20470, #29712, #33414.
Nz*telegram topic binding refresh failed (%s)TrQ   )rd   r¡   rT   rU   rV   )r=   r1   r    r¤   s   &&&$r   Ú_sync_telegram_topic_bindingÚ5GatewayTopicThreadsMixin._sync_telegram_topic_binding˜   sQ   € ð ×+Ñ+¨F×3Ò3Ùð	^Ø×/Ñ/°ÖFøÜô 	^Ü�L‰LÐEÀvÐX\ˆL×]ð	^ús   ›. ®#AÁAc               ó    € V ^8„  d   QhRRRR/# rg   r   )r   s   "r   r   r2   ¦   s   € ÷ >ñ >¸ð >È-ñ >r   c                óV   € V P                  V4      '       d   R# V P                  V4      # )u  Adapter-ingress recovery hook (sync, called off-loop before session keying): lobby recovery,
except when ``dm_topic_auto_transfer`` is on â€” then the root-DM source is left alone so
``_transfer_telegram_root_dm`` can open a fresh topic (and fall back to this recovery itself).N)Ú%_telegram_topic_auto_transfer_enabledÚ!_recover_telegram_lobby_thread_idr^   s   &&r   Ú!_recover_telegram_topic_thread_idÚ:GatewayTopicThreadsMixin._recover_telegram_topic_thread_id¦   s)   € ð ×5Ñ5°f×=Ò=ÙØ×5Ñ5°fÓ=Ð=r   c               ó    € V ^8„  d   QhRRRR/# rg   r   )r   s   "r   r   r2   ®   s   € ÷ ñ ¸ð È-ñ r   c                ó  € V P                  V4      '       d<   VP                  '       d*   VP                  '       d   V P                  V4      '       g   R# \	        VP
                  ;'       g    R4      pV'       d   W P                  9  d   R# V P                  4       pVf   R#  VP                  \	        VP                  4      V P                  V4      R7      pT;'       g    R	 Fy  p\	        TP                  R4      ;'       g    R4      \	        TP                  4      8X  g   KA  \	        TP                  R4      ;'       g    R4      pT'       d   Yb8w  d   Tu # Ru # 	  R#   \         d    \        P                  RRR7        R# i ; i)
a  Pin lobby-shaped topic-mode DM replies (missing ``message_thread_id`` or General) to the
user's most-recent bound topic. Never rewrite a non-lobby, unbound thread id: a brand-new DM
topic is also "unknown" until its first message is recorded. None = leave the source alone.Nr&   ©rN   rP   ztopic-recover: read failedTrQ   rO   r\   r   )rI   rN   rO   rX   r#   r\   r]   r?   Ú%list_telegram_topic_bindings_for_chatr8   rT   rU   rV   ru   )r=   r1   Úinboundr>   ÚbindingsÚbÚ	recovereds   &&     r   r«   Ú:GatewayTopicThreadsMixin._recover_telegram_lobby_thread_id®   s@  € ð
 ×$Ñ$ V×,Ò,°F·N·N°NÈ&Ï.Ï.È.Ø×4Ñ4°V×<Ò<áÜ�f×&Ñ&×,Ð,¨"Ó-ˆß�w×&FÑ&FÔFÙØ×*Ñ*Ó,ˆ
ØÒÙð	Ø!×GÑGÜ˜FŸN™NÓ+¸$×:[Ñ:[Ð\bÓ:cð Hó ˆHð —�˜R’ˆAÜ�1—5‘5˜Ó#×)Ð) rÓ*¬c°&·.±.Ó.AÖAÜ §¡ kÓ 2× 8Ð 8°bÓ9�	ß$-°)Ô2F�yÒPÈDÒPñ  ñ øô ô 	Ü�L‰LÐ5ÀˆLÔEÚð	ús   Â%5E% Å%"FÆ
Fc               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2   Ê   s   € ÷ kñ kÀ-ð kÐTXñ kr   c                ó¨   € V P                  V4      pVe   \        VRR4      MRp\        \        VRR4      ;'       g    / P                  R4      4      # )z²The RECEIVING bot's ``extra.dm_topic_auto_transfer`` (default False): under multiplexing each
bot owns its opt-in. Off keeps the v0.22 lobby recovery (#136567). No state.db read.NÚconfigÚextraÚdm_topic_auto_transfer)Ú_delivery_adapter_forr6   r   ru   )r=   r1   ÚadapterÚplatform_cfgs   &&  r   Ú+_telegram_dm_topic_auto_transfer_configuredÚDGatewayTopicThreadsMixin._telegram_dm_topic_auto_transfer_configuredÊ   sR   € ð ×,Ñ,¨VÓ4ˆØ;BÒ;N”w˜w¨°$Ô7ÐTXˆÜ¤¨°g¸tÓ D× JÐ JÈ×OÑOÐPhÓiÓjÐjr   c               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2   Ñ   s   € ÷ wñ w¸Mð wÈdñ wr   c                óV   € V P                  V4      ;'       d    V P                  V4      # )zZThe key is on and ``source`` is a ``/topic``-mode root DM (reads state.db: call off-loop).)r¿   r_   r^   s   &&r   rª   Ú>GatewayTopicThreadsMixin._telegram_topic_auto_transfer_enabledÑ   s'   € à×?Ñ?ÀÓG×vÐvÈD×LnÑLnÐouÓLvÐvr   c               ó    € V ^8„  d   QhRRRR/# )r   r1   r   r   zOptional[tuple[str, bool]]r   )r   s   "r   r   r2   Õ   s   € ÷ 9ñ 9°}ð 9ÐIcñ 9r   c              ƒ  óÔ  "  € VP                   '       dG   V P                  V4      '       d0   \        P                  ! V P                  V4      G Rj  x€L
 '       g   R# V P                  V4      pVe   \        VRR4      MRpRp\        V4      '       d/    V! \        VP                   4      \        R4      4      G Rj  x€L
 pV'       d:   \        P                  RVP                   VP                  V4       \        V4      R3# \        P                  ! V P                   V4      G Rj  x€L
 pV'       d   VR3# R#  Lé L~  \         d    \        P                  RRR7        L i ; i L>5i)	a[  Adapter-ingress transfer hook for an opted-in root-DM message (#139136).

``(thread_id, True)``: a fresh topic was created and the turn runs there. ``(thread_id, False)``:
creating it failed, so the message falls back to lobby recovery (the last bound topic).
``None``: not applicable (key off, not a topic-mode root DM) or nothing to recover to.
NÚ_create_dm_topicr'   z9Failed to auto-transfer Telegram root DM into a new topicTrQ   zBtelegram topic auto-transfer: chat=%s user=%s root -> new topic %sF)rN   r¿   ÚasyncioÚ	to_threadr_   r¼   r6   ÚcallableÚintr
   rT   rU   rV   ÚinforO   r#   r«   )r=   r1   r½   Úcreate_topicr\   rµ   s   &&    r   Ú_transfer_telegram_root_dmÚ3GatewayTopicThreadsMixin._transfer_telegram_root_dmÕ   s2  é € ð ——� d×&VÑ&VÐW]×&^Ò&^Ü$×.Ò.¨t×/QÑ/QÐSYÓZ×ZÖZÙØ×,Ñ,¨VÓ4ˆØELÒEX”w˜wÐ(:¸DÔAÐ^bˆØˆ	Ü�L×!Ò!ðiÙ".¬s°6·>±>Ó/BÄAÐFcÓDdÓ"e×e�	÷ Ü�K‰KÐ\ØŸ™¨¯©¸	ôCä�y“> 4Ð'Ð'Ü!×+Ò+¨D×,RÑ,RÐTZÓ[×[ˆ	ß%.�	˜5Ð!Ð8°DÐ8ñ [ñ føÜô iÜ—‘ÐXÐcg�Öhðiúñ \ùsk   ‚)E(¬$E(ÁD:Á	E(Á9E(Â(D> Â=D<Â>D> ÃE(Ã
AE(Ä'E&Ä(E(Ä4E(Ä<D> Ä>"E#Å E(Å"E#Å#E(c               ó    € V ^8„  d   QhRRRR/# )r   r1   r   r   Údictr   )r   s   "r   r   r2   ð   s   € ÷ tñ t¸]ð tÈtñ tr   c              ƒ  óZ  a"  € \        V P                  V4      RR4      pVe   \        VR4      '       g   RR/#  VP                  4       G Rj  x€L
 oR	 T3R
 llpRR/R Uu/ uF  qDT! T4      bK  	  upC#  L)  \         d    \
        P                  RRR7       RR/u # i ; iu upi 5i)z?Read Telegram private-topic capability flags via Bot API getMe.Ú_botNÚget_meÚcheckedFz1Failed to fetch Telegram getMe topic capabilitiesTrQ   c               ó   € V ^8„  d   QhRR/# )r   Únamer#   r   )r   s   "r   r   ÚOGatewayTopicThreadsMixin._get_telegram_topic_capabilities.<locals>.__annotate__û   s   € ÷ 	Bñ 	B˜ñ 	Br   c                óô   <€ \        SV 4      '       d   \        SV 4      # \        SR R4      p\        V\        4      '       d   W9   d	   W,          # \        S\        4      '       d   SP	                  V 4      # R# )Ú
api_kwargsN)rq   r6   Ú
isinstancerÐ   ru   )rÖ   rÙ   Úmes   & €r   Ú_fieldÚIGatewayTopicThreadsMixin._get_telegram_topic_capabilities.<locals>._fieldû   se   ø€ Ü�r˜4× Ò Ü˜r 4Ó(Ð(Ü   \°4Ó8ˆJÜ˜*¤d×+Ò+°Ô0BØ!Õ'Ð'Ü#-¨b´$×#7Ò#7�2—6‘6˜$“<ÐA¸TÐAr   )Úhas_topics_enabledÚallows_users_to_create_topics)r6   r¼   rq   rÓ   rT   rU   rV   )r=   r1   ÚbotrÜ   ÚkrÛ   s   &&   @r   Ú _get_telegram_topic_capabilitiesÚ9GatewayTopicThreadsMixin._get_telegram_topic_capabilitiesð   sº   øé € ä�d×0Ñ0°Ó8¸&À$ÓGˆØŠ;œg c¨8×4Ò4Ø˜uÐ%Ð%ð	&Ø—z‘z“|×#ˆB÷
	Bð 	Bð ˜4ÐsÑ:qÓ#rÑ:q°Q¡v¨a£y¢LÑ:qÑ#rÐsÐsñ $øÜô 	&Ü�L‰LÐLÐW[ˆLÔ\Ø˜uÐ%Ò%ð	&üò $sùsF   ƒ7B+»A: ÁA8ÁA: ÁB+Á#B&Á4B+Á8A: Á:&B#Â B+Â"B#Â#B+c               ó    € V ^8„  d   QhRRRR/# rš   r   )r   s   "r   r   r2     s   € ÷ Uñ U¸-ð UÈDñ Ur   c              ƒ  ón  "  € V P                  V4      pVe    VP                  '       d   \        VRR4      MRp\        V4      '       g   R#  V! \	        VP                  4      \        R4      4      G Rj  x€L
 pT'       g   R#  TP                  TP                  \        R4      R\        T4      /R	7      G Rj  x€L
 p\        TR
R4      p\        TRR4      pT'       d   Te   \        TR4      '       g   R#  TP                  \	        TP                  4      \	        T4      RR7      G Rj  x€L
  R#  L¾  \         d    \        P                  RRR7        R# i ; i L¤  \         d    \        P                  RRR7        R# i ; i L\  \         d    \        P                  RRR7        R# i ; i5i)zJCreate/pin the managed System topic after /topic activation when possible.NrÆ   zgateway.topic.system_topic_namez&Failed to create Telegram System topicTrQ   z gateway.topic.system_topic_intror\   )ÚmetadataÚ
message_idz*Failed to send Telegram System topic introrÒ   Úpin_chat_message)rN   rç   Údisable_notificationz)Failed to pin Telegram System topic intro)r¼   rN   r6   rÉ   rÊ   r
   rT   rU   rV   Úsendr#   rq   rè   )r=   r1   r½   rÌ   r\   Úsend_resultrç   rà   s   &&      r   Ú_ensure_telegram_system_topicÚ6GatewayTopicThreadsMixin._ensure_telegram_system_topic  sŽ  é € à×,Ñ,¨VÓ4ˆØELÒEXÐ]c×]k×]kÐ]k”w˜wÐ(:¸DÔAÐquˆÜ˜×%Ò%Ùð	Ù*¬3¨v¯~©~Ó+>ÄÐBcÓ@dÓe×eˆI÷ Ùð	Ø '§¡Ø—‘¤Ð"DÓ EÐQ\Ô^aÐbkÓ^lÐPmð !-ó !÷ ˆKô ! ¨l¸DÓAˆJô �g˜v tÓ,ˆß˜Sš[´¸Ð=O×0PÒ0PÙð	UØ×&Ñ&¬s°6·>±>Ó/BÌsÐS]ËÐuyÐ&Óz×zÒzñ% føÜô 	Ü�L‰LÐAÈDˆLÔQÚð	úñøô ô 	Ü�L‰LÐEÐPTˆLÔUÚð	úñ {øÜô 	UÜ�L‰LÐDÈtˆL×Tð	Uüs²   ‚'F5ª"F5Á(D6 Á5D4Á6D6 Á:F5ÂF5Â5E! Â:EÂ;E! Ã-F5Ã:3F Ä-F
Ä.F Ä2F5Ä4D6 Ä6"EÅF5ÅEÅF5ÅE! Å!"FÆF5ÆFÆF5Æ
F Æ"F2Æ.F5Æ1F2Æ2F5c               ó    € V ^8„  d   QhRRRR/# rš   r   )r   s   "r   r   r2   "  s   € ÷ Uñ U¸]ð UÈtñ Ur   c           	   ƒ  ó6  "  € V P                  V4      p\        \        4      P                  4       P                  R,          R,          pVe;   VP
                  '       d)   \        VR4      '       d   VP                  4       '       g   R#  TP                  VP
                  \        V4      \        R4      VP                  '       d   R\        VP                  4      /MRR7      G Rj  x€L
  R#  L  \         d    \        P                  RR	R
7        R# i ; i5i)zFSend the bundled BotFather Threads Settings screenshot when available.Úassetsz'telegram-botfather-threads-settings.jpgNÚsend_image_filez!gateway.topic.setup_image_captionr\   )rN   Ú
image_pathÚcaptionræ   z)Failed to send Telegram topic setup imageTrQ   )r¼   r   Ú__file__ÚresolveÚparentrN   rq   Úexistsrñ   r#   r
   r\   rT   rU   rV   )r=   r1   r½   rò   s   &&  r   Ú _send_telegram_topic_setup_imageÚ9GatewayTopicThreadsMixin._send_telegram_topic_setup_image"  sà   é € à×,Ñ,¨VÓ4ˆÜœ(“^×+Ñ+Ó-×4Ñ4°xÕ?ÐBkÕkˆ
ØŠ? &§.§. .¼ÀÐIZ×8[Ò8[Ðcm×ctÑct×cvÒcvÙð	UØ×)Ñ)ØŸ™´3°z³?ÌAÐNqÓLrØAG×AQ×AQÐAQ˜+¤s¨6×+;Ñ+;Ó'<Ñ=ÐW[ð *ó ÷ ô øô ô 	UÜ�L‰LÐDÈtˆL×Tð	UüsI   ‚ADÁ'DÂDÂ
AC0 Ã'C.Ã(C0 Ã,DÃ.C0 Ã0"DÄDÄDÄDc               ó    € V ^8„  d   QhRRRR/# r!   r   )r   s   "r   r   r2   2  s   € ÷ Rñ R°Cð R¸Cñ Rr   c                óx   € \        V4      p\        V4      ^x8:  d   V# VR,          P                  4       R,           # )zVBot API-safe forum topic name: names are 1-128 chars; keep room for multi-byte titles.:Néu   Nú...)r,   ÚlenÚrstrip©r=   r"   Úcleaneds   && r   Ú_sanitize_telegram_topic_titleÚ7GatewayTopicThreadsMixin._sanitize_telegram_topic_title2  s4   € ä! %Ó(ˆÜ˜g›,¨#Ô-ˆwÐQ°7¸4µ=×3GÑ3GÓ3IÈEÕ3QÐQr   c               ó    € V ^8„  d   QhRRRR/# r!   r   )r   s   "r   r   r2   7  s   € ÷ qñ q°Cð q¸Cñ qr   c                ó~   € \        V4      p\        V4      ^P8:  d   V# \        V^M4      P                  4       R,           # )z¬Discord-safe thread title: the 100-char cap is measured in UTF-16 code units (emoji count
double), so truncate with the UTF-16 helpers rather than Python code-point slices.rý   )r,   r   r   rÿ   r   s   && r   Ú_sanitize_discord_thread_titleÚ7GatewayTopicThreadsMixin._sanitize_discord_thread_title7  s>   € ô " %Ó(ˆÜ# GÓ,°Ô2ˆwÐpÔ8RÐSZÐ\^Ó8_×8fÑ8fÓ8hÐkpÕ8pÐpr   c               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2   ?  s   € ÷ 
ñ 
°=ð 
ÀTñ 
r   c                ó  € VP                   \        P                  8H  ;'       di    VP                  R8H  ;'       dR    \	        \        VRR4      4      ;'       d4    \	        VP                  4      ;'       d    \	        \        VRR4      4      # )z>Return True only for Discord threads Hermes just auto-created.ÚthreadÚauto_thread_createdFÚauto_thread_initial_nameN)rF   r   ÚDISCORDrH   rC   r6   r\   r^   s   &&r   Ú_is_discord_auto_thread_laneÚ5GatewayTopicThreadsMixin._is_discord_auto_thread_lane?  sŠ   € ð �O‰Oœx×/Ñ/Ñ/÷ Hð H°F×4DÑ4DÈÑ4P÷ Hð HÜ”W˜VÐ%:¸EÓBÓC÷Hð HÜHLÈV×M]ÑM]ÓH^÷Hð Hä”W˜VÐ%?ÀÓFÓGð	
r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r1   r   r�   r#   r   r   )r   s   "r   r   r2   G  s#   € ÷ %
ñ %
¸-ð %
ÐVYð %
Ð^kñ %
r   c                óJ  a a€ SP                   \        P                  8w  gM   SP                  R8w  g<   SP                  '       d*   SP
                  '       g   S P                  S4      '       d   S# S P                  P                  V4      pVf   S# R V V3R llpVP                  pV! V4      '       gÆ   S P                  P                  V4      pVe   VP                  VP                  4      MRpT;'       g    / P                  R4      pRpV'       dU   \        \        \         \"        4      ;_uu_ 4        \$        P&                  ! \(        P*                  ! V4      4      pRRR4       V! V4      '       g   S# \-        SRVP.                  R7      #   + '       g   i     L8; i)a‡  *source* with the auto-thread markers of the session's opening event, when that event
created this same native Discord thread.

Native Discord stamps the markers only on the opening event, so a later title retry on a
rebuilt agent arrives unmarked. The routing entry's ``origin`` is that opening source and
survives restarts. ``replace_source`` keeps the live transport owner and message id.r
  Nc               ó    € V ^8„  d   QhRRRR/# )r   ÚoriginzOptional[SessionSource]r   rC   r   )r   s   "r   r   ÚRGatewayTopicThreadsMixin._recover_discord_auto_thread_source.<locals>.__annotate__W  s   € ÷ 	ñ 	Ð&=ð 	À$ñ 	r   c                ó¤   <€ V R J;'       dE    \        V P                  4      \        SP                  4      8H  ;'       d    SP                  V 4      # ©N)r#   r\   r  )r  r=   r1   s   &€€r   Úopens_this_threadÚWGatewayTopicThreadsMixin._recover_discord_auto_thread_source.<locals>.opens_this_threadW  sO   ø€ à˜dÐ"÷ >ð >¤s¨6×+;Ñ+;Ó'<ÄÀF×DTÑDTÓ@UÑ'U÷ >ð >Ø×5Ñ5°fÓ=ðr   Úorigin_jsonT)r  r  )rF   r   r  rH   r\   Údelivered_via_upstream_relayr  Úsession_storeÚlookup_by_session_keyr  Ú_db_for_keyÚget_sessionrž   ru   r   Ú
ValueErrorÚKeyErrorÚ	TypeErrorr   Ú	from_dictÚjsonÚloadsr   r  )	r=   r1   r�   Úentryr  r  ÚdbÚrowrW   s	   ff&      r   Ú#_recover_discord_auto_thread_sourceÚ<GatewayTopicThreadsMixin._recover_discord_auto_thread_sourceG  s?  ù€ ð �O‰Oœx×/Ñ/Ô/°6×3CÑ3CÀxÔ3OÐW]×Wg×WgÐWgØ×2×2Ð2°d×6WÑ6WÐX^×6_Ò6_àˆMØ×"Ñ"×8Ñ8¸ÓEˆØŠ=ØˆM÷	ñ 	ð —‘ˆÙ  ×(Ò(ð ×#Ñ#×/Ñ/°Ó<ˆBØ68²n�"—.‘. ×!1Ñ!1Ô2È$ˆCØ—9�9˜"—/‘/ -Ó0ˆCØˆFßÜœj¬(´I×>Õ>Ü*×4Ò4´T·Z²ZÀ³_ÓE�F÷ ?á$ V×,Ò,Ø�ÜØ¨Àv×GfÑGfô
ð 	
÷	 ?×>ús   Ä7+FÆF"	c               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2   n  s   € ÷ 
ñ 
°]ð 
Àtñ 
r   c                ó  € VP                   \        P                  8H  ;'       d]    \        VP                  4      ;'       d@    VP
                  '       * ;'       d'    VP                  R9   ;'       d    \        VRR4      RJ # )u  Shape-only check: a relay-delivered Discord CHANNEL event whose reply the connector MAY
auto-thread (title-turn registration gate). Deliberately does NOT consult the send-result
cache â€” before delivery the feedback can't exist; the rename lane polls it at fire time.r  FT)ÚgroupÚchannel)rF   r   r  rC   rN   r\   rH   r6   r^   s   &&r   Ú_is_relay_discord_channel_laneÚ7GatewayTopicThreadsMixin._is_relay_discord_channel_lanen  sƒ   € ð
 �O‰Oœx×/Ñ/Ñ/÷ Oð O´D¸¿¹Ó4H÷ Oð OÐQW×QaÑQaÔMa÷ Oð OØ× Ñ Ð$8Ñ8÷Oð Oä˜Ð >ÀÓFÈ$ÐNð	
r   c               ó    € V ^8„  d   QhRRRR/# ©r   r1   r   r   úOptional[tuple[str, str]]r   )r   s   "r   r   r2   x  s   € ÷ ñ ¨mð Ð@Yñ r   c           	     óê  € ^ RI Hp VP                  \        P                  8w  g&   VP
                  '       d   \        VRR4      '       g   R# \        VRR4      pV'       d   \        V4      R3# \        V P                  V4      RR4      p\        V4      '       g   R# \        \        4      ;_uu_ 4        V! V! \        VP
                  4      4      4      uuRRR4       #   + '       g   i     R# ; i)u<  (thread_id, initial_name) when the RELAY connector auto-threaded our reply â€” the title-turn
sibling of _is_discord_auto_thread_lane (whose markers only exist from turn 2 on; the title
turn's source is the PARENT channel event).

Preferred: the connector's per-message ``prospective_thread_id`` stamp (anchor message id ==
the thread it will create), exact even when several auto-threads spawn from one channel;
the connector's created-name guard enforces no-clobber. Fallback: the per-chat send-result
cache (older connectors), which only ever renamed the FIRST thread.
)Ú_as_thread_infor  FNÚprospective_thread_idr&   Úauto_thread_info_for_chat)Úgateway.runr4  rF   r   r  rN   r6   r#   r¼   rÉ   r   rT   )r=   r1   r4  ÚprospectiveÚinfo_fns   &&   r   Ú_relay_auto_thread_infoÚ0GatewayTopicThreadsMixin._relay_auto_thread_infox  s´   € õ 	0à�O‰Oœx×/Ñ/Ô/°v·~·~°~Ü˜6Ð#AÀ5×IÒIáÜ˜fÐ&=¸tÓDˆßô ˜Ó$ bÐ)Ð)Ü˜$×4Ñ4°VÓ<Ð>YÐ[_Ó`ˆÜ˜× Ò ÙÜ”i× Õ Ù"¡7¬3¨v¯~©~Ó+>Ó#?Ó@÷ !× × Ñ áús   Â5!C!Ã!C2	c               ó    € V ^8„  d   QhRRRR/# r1  r   )r   s   "r   r   r2   ”  s   € ÷ ñ ¸-ð ÐLeñ r   c           	   ƒ  ó´  "  € ^ RI HpHp V P                  V4      pVe   V# \	        V P                  V4      RR4      p\        V4      '       d   VP                  '       g   R# V! RR4      ;'       g    Rp\        \        4      ;_uu_ 4        T! V! \        VP                  4      V4      G Rj  x€L
 4      uuRRR4       #  L  + '       g   i     R# ; i5i)a  ``_relay_auto_thread_info``, waited out until this turn delivers (the legacy send-result
path can only answer once the reply is sent; the caller asks at title time, one turn early).
The timeout is only a backstop for a turn that never sends: the turn's own inactivity limit.)r4  Ú
_float_envNÚwait_for_auto_thread_infoÚHERMES_AGENT_TIMEOUTi  )r7  r4  r>  r:  r6   r¼   rÉ   rN   r   rT   r#   )r=   r1   r4  r>  ÚknownÚwait_fnÚtimeouts   &&     r   Ú_await_relay_auto_thread_infoÚ6GatewayTopicThreadsMixin._await_relay_auto_thread_info”  s§   é € ÷ 	<à×,Ñ,¨VÓ4ˆØÒØˆLÜ˜$×4Ñ4°VÓ<Ð>YÐ[_Ó`ˆÜ˜× Ò ¨¯¯¨ÙáÐ3°TÓ:×BÐB¸dˆÜ”i× Õ Ù"©´°V·^±^Ó1DÀgÓ)N×#NÓO÷ !Ò Ù#N÷ !Ö áüs<   ‚ACÁ!CÁ3CÂ"CÂ/CÂ0CÂ7CÃCÃC	Ã	CNc          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r   r1   r   rž   r#   r"   Ú
relay_infor2  r   r›   r   )r   s   "r   r   r2   ¦  s=   € ÷ ,lñ ,lØ#ð,lØ14ð,lØ=@ð,là-ð,lð 
ñ,lr   c              ƒ  óÌ  "  € Vfh   \         P                  ! V P                  V4      G Rj  x€L
 '       g9   V P                  V4      '       g   R# V P	                  V4      G Rj  x€L
 pVf   R# \        V RR4      '       d   V P                  V4      MRp\        VRR4      pVf   R# VRJpV'       d
   V^ ,          M\        VP                  4      pV P                  V4      p	V'       d.   RRRVP                  '       d   \        VP                  4      MR/MR\        VRR4      /p
\        P                  R	Y‡'       d   R
MRV	4        V! W‰3/ V
B G Rj  x€L
 p\        P                  RV\        V4      4       R#  ELP EL L,  \         d0    \        P                  R\!        T4      P"                  RR7        R# \$         d    \        P'                  RRR7        R# i ; i5i)a  Best-effort semantic rename of a newly auto-created Discord thread. ``relay_info`` is the
connector's (thread_id, initial_name) feedback, supplied on the title turn where the source
is the parent-channel event without auto-thread markers (see _relay_auto_thread_info).NÚadaptersÚrename_threadÚprefer_connector_createdTÚparent_chat_idÚonly_if_current_namer  z:discord auto-thread rename: thread=%s lane=%s new_title=%rÚrelayÚnativez7discord auto-thread rename result: thread=%s applied=%sz<Discord semantic thread rename raised TypeError (adapter=%s)rQ   z@Failed to rename Discord auto-thread for generated session title)rÇ   rÈ   r  r.  rD  r6   r¼   r#   r\   r  rN   rU   rË   rC   r!  ÚwarningÚtypeÚ__name__rT   rV   )r=   r1   rž   r"   rG  r½   rJ  rN  Útarget_thread_idÚthread_nameÚrename_kwargsÚrenameds   &&&&&       r   Ú-_rename_discord_auto_thread_for_session_titleÚFGatewayTopicThreadsMixin._rename_discord_auto_thread_for_session_title¦  s½  é € ð Ò¬G×,=Ò,=¸d×>_Ñ>_ÐagÓ,h×&hÖ&hð ×6Ñ6°v×>Ò>ÙØ#×AÑAÀ&ÓI×IˆJØÒ!ÙÜ8?ÀÀjÐRV×8WÒ8W�$×,Ñ,¨VÔ4Ð]aˆÜ ¨¸$Ó?ˆØÒ ÙØ $Ð&ˆß,1˜: až=´s¸6×;KÑ;KÓ7LÐØ×9Ñ9¸%Ó@ˆ÷ ð (¨Ð/?ÐX^×Xf×XfÐXfÄÀVÇ^Á^ÔATÐlpÑqØ1´7¸6ÐC]Ð_cÓ3dÐeð 	ô 	�‰ØHØ®™g°H¸kô	
ð	lÙ)Ð*:ÑYÈ=ÑY×YˆGÜ�K‰KÐQÐScÔeiÐjqÓerÖsò? 'iò Jñ0 Zøäô 	Ü�N‰NØNÔPTÐU\ÓP]×PfÑPfÐquð ÷ ô ô 	lÜ�L‰LÐ[ÐfjˆL×kð	lüsˆ   ‚)G$«E;¬	G$¶G$ÁG$Á#E>Á$AG$Â36G$Ã*G$Ã?AG$ÅF ÅFÅ$F Å9G$Å>G$ÆF Æ6G!Æ9G$Æ<G!ÇG!ÇG$Ç G!Ç!G$c               ó$   € V ^8„  d   QhRRRRRR/# )r   r1   r   Úlabelr#   r   r›   r   )r   s   "r   r   r2   Ö  s#   € ÷ :ñ :¸ð :ÐZ]ð :Ðbfñ :r   c                ó¬  a€ ^ RI Hp  \        P                  ! 4       pVe   VP                  4       '       d   R# Tp\        \        4      ;_uu_ 4        ^ RI	H
p V! V4      pRRR4       V! V! V4      V\        S R2R7      pR V3R llp	Ve   VP                  V	4       R# R#   \         d    \        T RR4      p L¡i ; i  + '       g   i     Li; i)	zÝSchedule a best-effort rename coroutine onto the gateway loop from the auto-title thread.
The source is copied so the thread never shares the live dataclass with the loop; failures
are logged at debug and never propagate.)Úsafe_schedule_threadsafeÚ_gateway_loopNr   z failed to schedule)rU   Úlog_messagec               ó   € V ^8„  d   QhRR/# )r   r   r›   r   )r   s   "r   r   ÚQGatewayTopicThreadsMixin._schedule_rename_from_title_thread.<locals>.__annotate__ë  s   € ÷ 	@ñ 	@¨ñ 	@r   c                ó~   <€  V P                  4        R#   \         d    \        P                  R SRR7        R# i ; i)z	%s failedTrQ   N)ÚresultrT   rU   rV   )ÚfutrZ  s   &€r   Ú_log_rename_failureÚXGatewayTopicThreadsMixin._schedule_rename_from_title_thread.<locals>._log_rename_failureë  s5   ø€ ð@Ø—
‘
–øÜô @Ü—‘˜[¨%¸$�×?ð@ús   ƒ •#<»<)r7  r\  rÇ   Úget_running_loopÚRuntimeErrorr6   Ú	is_closedr   rT   Úgateway.session_identityr   rU   Úadd_done_callback)
r=   r1   Ú	make_cororZ  r\  ÚloopÚcopied_sourcer   Úfuturerd  s
   &&&f      r   Ú"_schedule_rename_from_title_threadÚ;GatewayTopicThreadsMixin._schedule_rename_from_title_threadÖ  sÈ   ø€ õ 	9ð	8Ü×+Ò+Ó-ˆDð Š<˜4Ÿ>™>×+Ò+ÙØˆÜ”i× Õ õ @Ù*¨6Ó2ˆM÷	 !ñ
 *Ù�mÓ$ d´6È%ÈÐPcÐGdô
ˆ÷	@ð 	@ð ÒØ×$Ñ$Ð%8Ö9ñ øô) ô 	8Ü˜4 °$Ó7ŠDð	8ú÷
 !× ús   ‰B% ÁCÂ%C Â?C ÃC	c               ó(   € V ^8„  d   QhRRRRRRRR/# ©r   r1   r   rž   r#   r"   r   r›   r   )r   s   "r   r   r2   ô  s+   € ÷ 
ñ 
¸}ð 
ÐZ]ð 
Ðfið 
Ðnrñ 
r   c                óä   a aaa€ S'       g   R# RoS P                  V4      '       g/   S P                  V4      oSf   S P                  V4      '       g   R# S P                  VVV VV3R lR4       R# )zJSchedule Discord auto-thread rename from the auto-title background thread.Nc                ó.   <€ SP                  V SSSR 7      # ))rG  )rW  )ÚcopiedrG  r=   rž   r"   s   &€€€€r   Ú<lambda>ÚSGatewayTopicThreadsMixin._schedule_discord_semantic_thread_rename.<locals>.<lambda>  s   ø€ ˜4×MÑMØ˜
 E°jð Nô r   zDiscord semantic thread rename)r  r:  r.  ro  )r=   r1   rž   r"   rG  s   f&ff@r   Ú(_schedule_discord_semantic_thread_renameÚAGatewayTopicThreadsMixin._schedule_discord_semantic_thread_renameô  se   û€ çÙØˆ
Ø×0Ñ0°×8Ò8ð
 ×5Ñ5°fÓ=ˆJØÒ!¨$×*MÑ*MÈf×*UÒ*UÙØ×/Ñ/Ø÷ð -ö	
r   c               ó(   € V ^8„  d   QhRRRRRRRR/# rr  r   )r   s   "r   r   r2   	  s+   € ÷ 
ñ 
¸Mð 
ÐWZð 
Ðcfð 
Ðkoñ 
r   c                ó®   a aa€ S'       d/   S P                  V4      '       d   S P                  V4      '       d   R# S P                  VV VV3R lR4       R# )z>Schedule a topic rename from the auto-title background thread.Nc                ó*   <€ SP                  V SS4      # r  )Ú(_rename_telegram_topic_for_session_title)ru  r=   rž   r"   s   &€€€r   rv  ÚPGatewayTopicThreadsMixin._schedule_telegram_topic_title_rename.<locals>.<lambda>  s   ø€ ˜4×HÑHÈÐQ[Ð]bÔcr   zTelegram topic title rename)rd   Ú$_telegram_topic_auto_rename_disabledro  )r=   r1   rž   r"   s   f&ffr   Ú%_schedule_telegram_topic_title_renameÚ>GatewayTopicThreadsMixin._schedule_telegram_topic_title_rename	  sA   ú€ ç˜D×8Ñ8¸×@Ò@ÀD×DmÑDmÐnt×DuÒDuÙØ×/Ñ/ØÞcØ)ö	
r   c               ó    € V ^8„  d   QhRRRR/# rB   r   )r   s   "r   r   r2     s   € ÷ nñ n¸=ð nÈTñ nr   c                ó
  € \        V RR4      pV'       d9   \        VRR4      '       d&   VP                  P                  VP                  4      MRpVf   R# \	        \        VRR4      ;'       g    / P                  R4      4      # )z_``gateway.platforms.telegram.extra.disable_topic_auto_rename``; default False (auto-rename on).r¹   NÚ	platformsFrº   Údisable_topic_auto_rename)r6   r„  ru   rF   r   )r=   r1   r¹   r¾   s   &&  r   r  Ú=GatewayTopicThreadsMixin._telegram_topic_auto_rename_disabled  sq   € ä˜˜x¨Ó.ˆß@FÌ7ÐSYÐ[fÐhl×KmÒKm�v×'Ñ'×+Ñ+¨F¯O©OÔ<ÐswˆØÒÙÜ¤¨°g¸tÓ D× JÐ JÈ×OÑOÐPkÓlÓmÐmr   c               ó(   € V ^8„  d   QhRRRRRRRR/# rr  r   )r   s   "r   r   r2     s1   € ÷ 2dñ 2dÀ]ð 2dÐ`cð 2dÐloð 2dÐtxñ 2dr   c              ƒ  ó<  "  € \         P                  ! V P                  V4      G Rj  x€L
 '       d%   VP                  '       d   VP                  '       g   R# V P                  V4      '       d   R# V P                  V4      pVe   \        \        V4      RR4      MRp\        V4      '       dJ    V! V\        VP                  4      \        VP                  4      4      p\        V\        4      '       d   R# \        V RR4      pVe�    VP                  \        VP                  4      \        VP                  4      V P                  V4      R7      G Rj  x€L
 pV'       d5   \        VP!                  R4      ;'       g    R4      \        V4      8w  d   R# Vf   R# V P'                  V4      p	 \        VR
R4      p
V
e<   V
! \        VP                  4      \        VP                  4      V	R7      G Rj  x€L
  R# \        VRR4      p\        VRR4      ;'       g    \        VRR4      pVf   R#  V! \)        VP                  4      \)        VP                  4      V	R7      G Rj  x€L
  R#  ELE  \         d    Rp ELŸi ; i EL-  \         d    \"        P%                  RRR	7        R# i ; i Lº LK  \*        \,        3 d-    T! TP                  TP                  T	R7      G Rj  x€L 
   R# i ; i  \         d    \"        P%                  RRR	7        R# i ; i5i)zLBest-effort rename of a Telegram DM topic when Hermes auto-titles a session.NÚ_get_dm_topic_infor;   ©rN   r\   rP   rž   r&   z5Failed to verify Telegram topic binding before renameTrQ   Úrename_dm_topic)rN   r\   rÖ   rÒ   Úedit_forum_topicÚeditForumTopic)rN   Úmessage_thread_idrÖ   z8Failed to rename Telegram topic for auto-generated title)rÇ   rÈ   rd   rN   r\   r  r¼   r6   rQ  rÉ   r#   rT   rÚ   rÐ   Úget_telegram_topic_bindingr8   ru   rU   rV   r  rÊ   r!  r  )r=   r1   rž   r"   r½   Úget_infoÚoperator_topicr>   ÚbindingÚ
topic_nameÚrename_topicrà   rŒ  s   &&&&         r   r}  ÚAGatewayTopicThreadsMixin._rename_telegram_topic_for_session_title  s¹  é € ä×&Ò& t×'CÑ'CÀVÓL×LÖLÐTZ×Tb×TbÐTbÐjp×jz×jzÐjzÙð ×4Ñ4°V×<Ò<Ùð
 ×,Ñ,¨VÓ4ˆØIPÒI\”7œ4 ›=Ð*>ÀÔEÐbfˆÜ�H×Òð&Ù!)¨'´3°v·~±~Ó3FÌÈF×L\ÑL\ÓH]Ó!^�ô ˜.¬$×/Ò/ÙÜ˜T =°$Ó7ˆ
ØÒ!ð	Ø *× EÑ EÜ §¡Ó/¼3¸v×?OÑ?OÓ;PØ!%×!BÑ!BÀ6Ó!Jð !Fó !÷ �÷ œs 7§;¡;¨|Ó#<×#BÐ#BÀÓCÄsÈ:ÃÔVÙð Š?ÙØ×8Ñ8¸Ó?ˆ
ð	dÜ" 7Ð,=¸tÓDˆLØÒ'Ù"¬3¨v¯~©~Ó+>Ì#Èf×N^ÑN^ÓJ_ÐfpÔq×qÐqÙÜ˜' 6¨4Ó0ˆCÜ& sÐ,>ÀÓE×mÐmÌÐQTÐVfÐhlÓImÐØÒ'ÙðtÙ&¬s°6·>±>Ó/BÔVYÐZ`×ZjÑZjÓVkÐr|Ô}×}Ò}òY Møô ô &Ø!%“ð&úòøô ô Ü—‘ÐTÐ_c�ÔdÚðúñ rñ ~øÜœzÐ*ô tÙ&¨v¯~©~ÐQW×QaÑQaÐhrÔs×sÔsðtûäô 	dÜ�L‰LÐSÐ^bˆL×cð	düs  ‚%L§I,¨	L²LÁLÁLÁ/A LÂ00I/ Ã )LÄ
AJ ÅJÅJ Å#J Æ J ÆLÆ/AK3 Ç4J/Ç5K3 Ç9LÇ; K3 ÈK3 È.LÈ14J3 É%J1É&J3 É*LÉ/J É<LÉ?J Ê LÊJ Ê"J,Ê(LÊ+J,Ê,LÊ/K3 Ê1J3 Ê33K0Ë&K)Ë'K0Ë,K3 Ë-LË/K0Ë0K3 Ë3"LÌLÌLÌLc               ó    € V ^8„  d   QhRRRR/# r0   r   )r   s   "r   r   r2   Q  s   € ÷ 0ñ 0À-ð 0ÐTWñ 0r   c           	   ƒ  óŠ  "  € V P                   '       g   ^ RIHp V! \        R4      R7      # \	        VP
                  ;'       g    R4      pV'       g   \        R4      # V P                  V4      pRp\        \        4      ;_uu_ 4        V P                   P                  T\	        VP                  ;'       g    R4      VR7      G Rj  x€L
 pRRR4       V'       g   \        R	4      #  V P                   P                  W4R
7      G Rj  x€L
  T P                  T4      pT'       d   RMR F9  p\        YR4      p	\!        T	\"        4      '       g   K'  T	P%                  TR4       K;  	  \        R4      #  L©  + '       g   i     L¯; i L~  \         d-   p\        P                  R4       \        RTR7      u Rp?# Rp?ii ; i5i)z5Cleanly disable topic mode for a chat via /topic off.)Úformat_session_db_unavailablez,gateway.shared.session_db_unavailable_prefix)Úprefixr&   zgateway.topic.no_chat_idFrM   Nzgateway.topic.mode_not_enabledr°   z%Failed to disable Telegram topic modezgateway.topic.disable_failed)Úerrorzgateway.topic.mode_disabled)r}   rƒ   r   )r;   Úhermes_stater˜  r
   r#   rN   r8   r   rT   rS   rO   Údisable_telegram_topic_moderU   Ú	exceptionrj   r6   rÚ   rÐ   Úpop)
r=   r1   r˜  rN   rP   Úcurrently_enabledÚexcÚcooldown_keyrm   Ústores
   &&        r   Ú%_disable_telegram_topic_mode_for_chatÚ>GatewayTopicThreadsMixin._disable_telegram_topic_mode_for_chatQ  s|  é € à××ÐÝBÙ0¼Ð:hÓ8iÔjÐjÜ�f—n‘n×*Ð*¨Ó+ˆßÜÐ/Ó0Ð0Ø×8Ñ8¸Ó@ˆØ!ÐÜ”i× Õ Ø&*×&6Ñ&6×&UÑ&UØ¬¨V¯^©^×-AÐ-A¸rÓ)BÐQ]ð 'Vó '÷ !Ð÷ !÷ !ÜÐ5Ó6Ð6ð	@Ø×"Ñ"×>Ñ>ÀwÐ>Ój×jÐjð ×8Ñ8¸Ó@ˆßWcÑSÐikÒkˆDÜ˜D¨Ó-ˆEÜ˜%¤×&Ô&Ø—	‘	˜,¨Ö-ñ lô Ð.Ó/Ð/ñ#!÷ !× úñ køÜô 	@Ü×ÑÐDÔEÜÐ3¸3Ô?Õ?ûð	@üs�   ‚AGÁGÁ5GÂ	?E4ÃE2Ã	E4ÃGÃGÃ)F	 ÄFÄ	F	 ÄGÄ&&GÅ!GÅ2E4Å4F	Å?GÆF	 Æ	G Æ!F;Æ5G Æ6GÆ;G Ç Gc               ó    € V ^8„  d   QhRRRR/# r0   r   )r   s   "r   r   r2   o  s   € ÷  ñ  Àð  ÐRUñ  r   c           	   ƒ  	óð  "  € \        R 4      R\        R4      R.p V P                  P                  \        VP                  4      \        VP
                  4      V P                  V4      ^
R7      G Rj  x€L
 pV'       Ed   VP                  \        R4      4       V Fœ  p\        VP                  R	4      ;'       g    R4      P                  4       pTP                  R
VP                  R4      ;'       g    \        R4       RVP                  R4      ;'       g    R R2V'       d   RV 2MR,           4       Kž  	  VP                  R\        R4      .\        4       O\        RV^ ,          P                  R4      R7      N4       M0VP                  \        R4      R\        R4      .\        4       O4       RP                  V4      #  ELU  \         d    \        P                  RRR7       . p ELzi ; i5i)zgateway.topic.status_enabledr&   zgateway.topic.status_how_to)rN   rO   rP   ÚlimitNz)Failed to list unlinked Telegram sessionsTrQ   zgateway.topic.previous_unlinkedÚpreviewz- r"   zgateway.topic.untitled_sessionu    â€” `ÚidÚ`u    â€” zgateway.topic.restore_onezgateway.topic.restore_example©rž   zgateway.topic.no_unlinkedzgateway.topic.restore_laterÚ
)r
   r;   Ú(list_unlinked_telegram_sessions_for_userr#   rN   rO   r8   rT   rU   rV   Úappendru   r*   Úextendr   Újoin)r=   r1   ÚlinesÚsessionsÚsessionr¨  s   &&    r   Ú#_telegram_topic_root_status_messageÚ<GatewayTopicThreadsMixin._telegram_topic_root_status_messageo  sÅ  é € ÜÐ1Ó2°B¼Ð:WÓ8XÐZ\Ð]ˆð	Ø!×-Ñ-×VÑVÜ˜FŸN™NÓ+´S¸¿¹Ó5HØ!×>Ñ>¸vÓFÈbð Wó ÷ ˆH÷ ˆ8Ø�L‰LœÐ<Ó=Ô>Û#�Ü˜gŸk™k¨)Ó4×:Ð:¸Ó;×AÑAÓC�Ø—‘Ø˜Ÿ™ WÓ-×TÐT´Ð3SÓ1TÐUÐU[Ð\c×\gÑ\gÐhlÓ\m×\sÐ\sÐqsÐ[tÐtuÐvß,3˜˜w˜iÑ(¸õ=öñ $ð �L‰L˜"œaÐ ;Ó<ð `Ô?SÓ?Uð `ÜÐ;ÈÐQRÍÏÉÐX\ÓH]Ô^ð`õ að �L‰Lœ!Ð7Ó8¸"¼aÐ@]Ó>^ÐxÔauÓawÐxÔyØ�y‰y˜ÓÐò'øô ô 	Ü�L‰LÐDÈtˆLÔTØ‹Hð	üsZ   ‚G6œAG Á3GÁ4G Á8G6Â;G6Â=8G6Ã6$G6ÄG6Ä(B G6ÇG Ç$G3Ç/G6Ç2G3Ç3G6c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úeventr   Úraw_session_idr#   r   r   )r   s   "r   r   r2   ‡  s(   € ÷ )tñ )t¸<ð )tÐY\ð )tÐadñ )tr   c           
   ƒ  ó¶  "  € VP                   pV P                  pVP                  VP                  4       4      G Rj  x€L
 pV'       d   VP	                  V4      G Rj  x€L
 MRpV'       g   \        RVP                  4       R7      # \        VP                  R4      ;'       g    R4      R8w  d   \        R4      # \        VP                  R4      ;'       g    R4      \        VP                  4      8w  d   \        R	4      # VP                  VR7      G Rj  x€L
 pV P                  V4      pVP                  \        VP                  4      \        VP                  4      VR
7      G Rj  x€L
 p	\        R4      p
V'       d!   V	'       d   V	P                  R4      V8w  d   V
#  VP                  \        VP                  4      \        VP                  4      \        VP                  4      V P                  V4      VRVR7      G Rj  x€L
  TP#                  T4      G Rj  x€L
 ;'       g    TpRp\%        \&        4      ;_uu_ 4        \)        TP+                  T4      G Rj  x€L
 4       F_  pTP                  R4      R8w  d   K  \-        T4      pTf   K,  TP                  R4      '       g   KE  \        TP                  R4      4      p M	  RRR4       \        RTR7      pTT'       d   \        RTR7      ,           # R,           #  ELÊ EL¬ ELõ EL¥ EL  \          d   pR\        T4      9   d   T
u Rp?# h Rp?ii ; i EL! Lá  + '       g   i     L€; i5i)zBRestore an existing Telegram-owned Hermes session into this topic.Nzgateway.topic.session_not_foundr«  r1   r&   Útelegramz"gateway.topic.not_telegram_sessionrO   zgateway.topic.not_your_sessionrŠ  zgateway.topic.already_linkedrž   Úrestored)rN   r\   rO   r�   rž   Úmanaged_moderP   zalready linkedÚroleÚ	assistantÚcontentzgateway.topic.restoredr+   z#gateway.topic.restored_last_message)Útext)r1   r;   Úresolve_session_idr*   r  r
   r#   ru   rO   Ú#is_telegram_session_linked_to_topicr8   r�  rN   r\   rŸ   Ú_session_key_for_sourcer  Úget_session_titler   rT   ÚreversedÚget_messagesr   )r=   r·  r¸  r1   r&  rž   r³  ÚlinkedÚtopic_profileÚcurrent_bindingÚalready_linkedr   r"   Úlast_assistantÚmessageÚ	projectedÚresponses   &&&              r   Ú_restore_telegram_topic_sessionÚ8GatewayTopicThreadsMixin._restore_telegram_topic_session‡  sÃ  é € à—‘ˆØ×ÑˆØ×0Ñ0°×1EÑ1EÓ1GÓH×Hˆ
ß6@˜Ÿ™ zÓ2×2Ð2ÀdˆßÜÐ6À>×CWÑCWÓCYÔZÐZÜˆw�{‰{˜8Ó$×*Ð*¨Ó+¨zÔ9ÜÐ9Ó:Ð:Üˆw�{‰{˜9Ó%×+Ð+¨Ó,´°F·N±NÓ0CÔCÜÐ5Ó6Ð6Ø×=Ñ=ÈÐ=ÓT×TˆØ×9Ñ9¸&ÓAˆØ "× =Ñ =Ü˜Ÿ™Ó'´3°v×7GÑ7GÓ3HÐWdð !>ó !
÷ 
ˆô Ð9Ó:ˆßŸ?¨o×.AÑ.AÀ,Ó.OÐS]Ô.]Ø!Ð!ð		Ø×(Ñ(Ü˜FŸN™NÓ+´s¸6×;KÑ;KÓ7LÔVYÐZ`×ZhÑZhÓViØ ×8Ñ8¸Ó@ÈZÐfpØ*ð )ó ÷ ð ð ×*Ñ*¨:Ó6×6×DÐD¸*ˆØˆÜ”i× Õ Ü#¨"¯/©/¸*Ó*E×$EÖF�Ø—;‘;˜vÓ&¨+Ô5ÙÜBÀ7ÓK�	ØÔ(¨Y¯]©]¸9×-EÔ-EÜ%(¨¯©°yÓ)AÓ%B�NÙñ G÷ !ô Ð-°UÔ;ˆØ×\jœ1ÐBÈÔXÕsÐsÐprÕsÐsòK IÚ2ò Uò
òøô
 ô 	Ø¤3 s£8Ô+Ø%Õ%Øûð	úò 7ñ %F÷ !× üsõ   ‚;M½L¾MÁ
MÁL
ÁMÁ-7MÂ%3MÃ?MÄLÄAMÅ+LÅ,MÆMÆ$A#L ÈLÈL ÈMÈ MÈ!
MÈ,MÉMÉ"MÉ#/MÊMÊ0MË:MÌ
MÌMÌMÌL ÌL>Ì!L9Ì2L>Ì3MÌ8L9Ì9L>Ì>MÍMÍM	ÍMr   r  )/rR  Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ústaticmethodr8   r?   rI   rX   r_   rd   rj   ry   r   r…   r‹   r�   r“   r—   r¡   r¦   r¬   r«   r¿   rª   rÍ   râ   rì   rø   r  r  r  r(  r.  r:  rD  rW  ro  rx  r€  r  r}  r£  r´  rÏ  Ú__static_attributes__r   r   r   r.   r.   (   s	  † Ù`ð ôPó ðPòVð
 ôQó ðQõõ"
õ
õ]õõ@õBõ-õ+õ_õ'õ
	
õ^õ>õõ8kõwõ9õ6tõ*Uõ:Uõ Rõ
qõ
õ%
õN
õõ8÷$,lõ`:õ<
õ*
õnõ2dõl0õ< ÷0)tñ )tr   r.   )*rÔ  Ú
__future__r   rÇ   r#  Úloggingr(   rs   Ú
contextlibr   Úpathlibr   Útypingr   r   r   Úagent.compaction_displayr   Ú
agent.i18nr
   Úgateway.configr   Úgateway.platforms.baser   r   Úgateway.platforms.eventr   Úgateway.sessionr   ri  r   Úutilsr   r7  r   Úgateway.run_turn_runnerr   Ú	getLoggerrU   r   r,   r.   r   r   r   Ú<module>rå     sx   ðñDõ #ã Û Û Û 	Û Ý Ý ß 1Ñ 1å KÝ Ý #ß HÝ 0Ý )Ý 3Ý !çÝ)Ý2ð 
×	Ò	˜=Ó	)€õRõ]÷H
tó H
tr   