+
    jHàjì'  ã                   óø   € R t ^ RIt^ RIHtHt ^ RIHt ^ RIt^ RIt^ RI	H
t
Ht ]P                  ! ]4      t]! RR7       ! R R4      4       tR	 tR
 tR tR tR tR tR tR tR tR tR tR tR tR tR tR# )aI  Busy same-sender bursts become one shared-runtime admission.

Main merged a busy photo burst into the pending slot and debounced queue-mode text from one sender
(``BasePlatformAdapter._queue_text_debounce``) so a thought split over two messages ran as one
turn. The authority FIFO admits each input as it arrives, so the burst is held here for main's
bounded window first, then committed once through ``dispatch_shared_busy``. Every absorbed caller
returns only after that commit, with its acceptance copied from it (committed before ACK), and
input that arrives later never commits before the burst. An adapter declaring
``serial_receive_loop`` (Signal, IRC, ...) delivers a chat's next input only after this returns, and
returning triggers no acknowledgement, so its caller returns once the input is held, as main
returned once merged. Its reader still never runs ahead of what it returned on: a chat holds at
most one uncommitted burst (the next one waits for that commit, main's backpressure), and a
command first waits until every earlier input of that reader has committed (``burst_gate``).
N)Ú	dataclassÚfield)Úpartial)ÚMessageEventÚMessageTypeF)Úeqc                   óF   a € ] tR t^t o RtRt]! ]R7      tV 3R lt	Rt
V tR# )Ú_BurstN)Údefault_factoryc                óÆ   <€ V ^8„  d   Qh/ S[ ;R&   S[P                  ;R&   S[;R&   S[;R&   S[P                  R,          ;R&   S[P                  R,          ;R&   S[;R&   # )	é   ÚheadÚdoneÚfirst_tsÚlast_tsNÚtimerÚcommitÚabsorbed)r   ÚasyncioÚFutureÚfloatÚTaskÚlist)ÚformatÚ__classdict__s   "€ÚB/home/ubuntu/.hermes/hermes-agent/gateway/session_ingress_burst.pyÚ__annotate__Ú_Burst.__annotate__   sr   ø‡ ‚ á
Ññ ñ �.‰.Ññ ñ �Oñ	 ñ
 �Nñ ñ �<‰<˜$ÕÑ%ñ ñ �L‰L˜4ÕÑ&ñ ñ Ñ0ò ó    © )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__r   r   r   r   r   Ú__annotate_func__Ú__static_attributes__Ú__classdictcell__)r   s   @r   r	   r	      s"   ø‡ € ð "&€EØ"&€FÙ¨4Ô0€H÷ ƒ r   r	   c                 óž   € VP                   \        P                  8X  d   VP                  '       g   R # V P	                  V4      '       d   R# R# )ÚphotoÚtextN)Úmessage_typer   ÚPHOTOÚinternalÚ!_is_queue_text_debounce_candidate)ÚadapterÚevents   &&r   Ú_kindr0   %   s<   € Ø×Ñœ[×.Ñ.Ô.°u·~·~°~ÙØ×>Ñ>¸u×EÒEˆ6ÐOÈ4ÐOr   c                 ó:   € V P                   P                  V/ 4      # ©N)Ú__dict__Ú
setdefault)r.   Únames   &&r   Ú_stater6   +   s   € Ø×Ñ×&Ñ& t¨RÓ0Ð0r   c                 ó   € \        V R R4      # )Úserial_receive_loopF)Úgetattr)r.   s   &r   Ú_serialr:   /   s   € Ü�7Ð1°5Ó9Ð9r   c                ó~   a a€ \         ;QJ d     V V3R lR 4       F  '       g   K   R# 	  R# ! V V3R lR 4       4      # )zNA burst is held or committing: later input for the route must queue behind it.c              3   ób   <"  € T F$  pSSP                   P                  VR4      9   x € K&  	  R # 5i)Nr   )r3   Úget)Ú.0r5   r.   Úsession_keys   & €€r   Ú	<genexpr>Ú#holds_busy_burst.<locals>.<genexpr>5   s+   øé € ÐuÑItÀˆ{˜g×.Ñ.×2Ñ2°4¸Ó<Ö<ÓItùs   ƒ,/TF)Ú_shared_burstsÚ_shared_burst_commits)Úany)r.   r?   s   ffr   Úholds_busy_burstrE   3   s.   ù€ ç‹3ÕuÑItÓu�3Œ3ÐuŠ3Ðuˆ3ÕuÑItÓuÓuÐur   c              ƒ  óÆ  "  € V P                  V4      '       d   \        W4      # VP                  4       ;p'       Ed   \        V 4      '       Ed   ^ RIHp V! V4      '       d   \        W4       \        V P                  P                  R/ 4      P                  4       4       F  w  rV\        WV4       K  	  \        V P                  P                  R/ 4      P                  4       4      ;p'       d   \        P                  ! V4      G Rj  x€L
  \        V P                  P                  RR4      4      ;p'       d   \        P                  ! V4      G Rj  x€L
  R#  LQ L5i)aÍ  ``handle_message``'s entry check. True: a held or committing burst owns the route, so this
shared-runtime input must queue behind it. A command on a serial reader first waits for every
input that reader already returned on, as main's reader reached it only after their commits:
/stop, /new and /reset drop their own chat's held burst (main dropped the debounce buffer),
every other held burst commits now, and every pending commit lands before the command runs.)Úis_interrupt_then_dispatchrB   rC   NÚ_uncommitted_inputsFr   )Ú_shared_runtime_owns_inputrE   Úget_commandr:   Úhermes_cli.commandsrG   Údiscard_busy_burstr   r3   r=   ÚitemsÚ_flushÚvaluesr   Úwait)	r.   r/   r?   ÚcmdrG   ÚkeyÚburstÚpendingÚhelds	   &&&      r   Ú
burst_gaterV   8   s  é € ð ×)Ñ)¨%×0Ò0Ü Ó5Ð5Ø× Ñ Ó"Ð"ˆ×"¬°×(8Ó(8ÝBÙ% c×*Ò*Ü˜wÔ4Ü˜w×/Ñ/×3Ñ3Ð4DÀbÓI×OÑOÓQÖR‰JˆCÜ�7 Ö'ñ Sä˜7×+Ñ+×/Ñ/Ð0GÈÓL×SÑSÓUÓVÐVˆ7ÖVÜ—,’,˜wÓ'×'Ð'Ü˜×(Ñ(×,Ñ,Ð-BÀBÓGÓHÐHˆ4ÖHÜ—,’,˜tÓ$×$Ð$Ùñ (á$ùs0   ‚;E!¾%E!Á$B'E!ÄEÄA
E!ÅEÅE!ÅE!c              ƒ  ó€  "  € ^ RI Hp ^ RIHp \	        W4      \        V R4      reVP                  V4      ;peÙ   Ve«   V\	        WP                  4      8X  d‘   V P                  VP                  V4      '       do   V! W'P                  /W!VR8H  R7       VP                  P                  V4       \        P                  ! 4       Vn        \        WV4       \        WV4      G Rj  x€L
 # \         P"                  ! \%        WV4      4      G Rj  x€L
  Kí  \        V R4      P                  V4      pVe_   Ve[   VP'                  4       '       gE   \)        V 4      '       d4   \         P*                  ! V04      G Rj  x€L
  \-        WV4      G Rj  x€L
 # Vf5   Ve    \         P*                  ! V04      G Rj  x€L
  V! WV4      G Rj  x€L
 # \        P                  ! 4       p	\/        V\         P0                  ! 4       P3                  4       W™4      ;qvV&   \        WV4       \        WV4      G Rj  x€L
 #  ELK EL& L½ L« L† Lw L5i)zs``dispatch_shared_busy`` for one busy input, merging a same-sender PHOTO+PHOTO or
queue-mode TEXT+TEXT burst first.)Úmerge_pending_message_event©Údispatch_shared_busyrB   Nr)   )Ú
merge_textrC   )Úgateway.platforms.baserX   Úgateway.session_ingressrZ   r0   r6   r=   r   Ú_can_merge_text_debounce_eventsr   ÚappendÚtimeÚ	monotonicr   Ú_armÚ	_acceptedr   ÚshieldrN   r   r:   rP   Údispatch_busy_burstr	   Úget_running_loopÚcreate_future)
r.   r/   r?   rX   rZ   ÚkindÚburstsrS   ÚpreviousÚnows
   &&&       r   re   re   M   sÍ  é € õ CÝ<Ü˜Ó(¬&°Ð:JÓ*Kˆ&Ø—J‘J˜{Ó+Ð+ˆ5Ò
8ØÒ ¬¨g·z±zÓ(BÔ BÀw×GnÑGnØ—
‘
˜E÷H#ò H#á'¨·j±jÐ(AÀ;ÐbfÐjpÑbpÕqØ�N‰N×!Ñ! %Ô(Ü ŸNšNÓ,ˆEŒMÜ� uÔ-Ü" 7°5Ó9×9Ð9Ü�nŠnœV G¸%Ó@ÓA×AÒAÜ�gÐ6Ó7×;Ñ;¸KÓH€HØÒ˜HÒ0¸¿¹¿ºÌWÐU\×M]ÒM]Ü�lŠl˜H˜:Ó&×&Ð&Ü(¨¸ÓE×EÐEØ‚|ØÒÜ—,’, ˜zÓ*×*Ð*Ù)¨'¸+ÓF×FÐFÜ
�.Š.Ó
€CÜ"(¨´×0HÒ0HÓ0J×0XÑ0XÓ0ZÐ\_Ó"eÐe€E�;ÑÜˆ˜uÔ%Ü˜7¨5Ó1×1Ð1ò :ÚAñ 	'ÙEñ +ÙFñ 2ùsŒ   ‚A7H>Á:A)H>Ã#H.Ã$'H>ÄH1Ä>H>Å+H>Å6H4Å7H>Æ
H6Æ&H>Æ1H8Æ2H>ÇH:ÇA&H>È)H<È*H>È1H>È4H>È6H>È8H>È:H>È<H>c              ƒ   ó¾   "  € \        V 4      '       d   R # \        P                  ! VP                  4      G R j  x€L
  VP                  P
                  Vn        R #  L!5ir2   )r:   r   rd   r   r   Ú_gateway_accepted)r.   rS   r/   s   &&&r   rc   rc   j   s@   é € Üˆw×ÒÙÜ
�.Š.˜Ÿ™Ó
$×$Ð$Ø#Ÿj™j×:Ñ:€EÖñ %ùs   ‚7A¹Aº"Ac                 ó†   € V P                   P                  V4       VP                  V P                   P                  4       V# r2   )Ú_background_tasksÚaddÚadd_done_callbackÚdiscard)r.   Útasks   &&r   Ú_trackrt   q   s5   € Ø×Ñ×!Ñ! $Ô'Ø×Ñ˜7×4Ñ4×<Ñ<Ô=Ø€Kr   c                 ó�  a aaa€ SP                   e   SP                   P                  4        \        R\        SP                  S P
                  ,           SP                  S P                  ,           4      \        P                  ! 4       ,
          4      oV VVV3R lp\        S \        P                  ! V! 4       4      4      Sn         R # )Ng        c               “   ó¦   <"  € \         P                  ! S4      G R j  x€L
  \         P                  ! \        S SS4      4      G R j  x€L
  R #  L/ L5ir2   )r   Úsleeprd   rN   )r.   rS   Údelayr?   s   €€€€r   ÚfireÚ_arm.<locals>.fire}   s;   øé € Ü�mŠm˜EÓ"×"Ð"Ü�nŠnœV G¨[¸%Ó@ÓA×AÒAñ 	#ÙAùs!   ƒA�Až(AÁAÁAÁA)r   ÚcancelÚmaxÚminr   Ú_busy_text_debounce_secondsr   Ú_busy_text_hard_cap_secondsr`   ra   rt   r   Úcreate_task)r.   r?   rS   ry   rx   s   fff @r   rb   rb   w   s�   û€ Ø‡{�{ÒØ�‰×ÑÔÜ�”S˜Ÿ™¨×)LÑ)LÕLØŸ™¨'×*MÑ*MÕMóOÜQU×Q_ÒQ_ÓQaõbó c€E÷Bð Bô ˜¤'×"5Ò"5±d³fÓ"=Ó>€E†Kr   c                ó2  aa€ VP                   fý   \        V R4      \        V R4      upoVP                  S4      VJ d   VS VP                  \        P
                  ! 4       Jd   VP                  P                  4        \        V \        P                  ! \        V SVSP                  S4      4      4      4      ;Vn         SS&   VP                   P                  VV3R l4       VP                   P                  \        \        V4      4       VP                   # )zJStart committing ``burst`` (once), after any earlier commit for the route.rB   rC   c                 ó\   <€ SP                  S4      V J ;'       d    SP                  S4      # r2   )r=   Úpop)rs   r?   Útailss   &€€r   Ú<lambda>Ú_flush.<locals>.<lambda>�   s+   ø€ °E·I±I¸kÓ4JÈdÐ4R×4mÐ4mÐW\×W`ÑW`ÐalÓWmÐ4mr   )r   r6   r=   r   r   Úcurrent_taskr{   rt   r€   Ú_commitrq   r   Ú_settle)r.   r?   rS   ri   r„   s   &f& @r   rN   rN   ƒ   sÝ   ù€ à‡|�|ÒÜ˜wÐ(8Ó9¼6À'ÐKbÓ;cˆˆ�Ø�:‰:�kÓ" eÓ+Ø�{Ð#Ø�;‰;œg×2Ò2Ó4Ó4Ø�K‰K×ÑÔ Ü,2°7¼G×<OÒ<OÜ�G˜[¨%°·±¸;Ó1GÓHó=Jó -Kð 	KˆŒ�u˜[Ñ)à�‰×&Ñ&Õ'mÔnØ�‰×&Ñ&¤w¬w¸Ó'>Ô?Ø�<‰<Ðr   c              ƒ   ó.  "  € ^ RI Hp Ve    \        P                  ! V04      G Rj  x€L
   V! WP                  VRR7      G Rj  x€L
  R#  L$ L  \
         d8    \        T 4      '       g   h \        P                  RT P                  T4        R# i ; i5i)é    rY   NT)Údurablez%[%s] Busy burst for %s was not queued)
r]   rZ   r   rP   r   Ú	Exceptionr:   ÚloggerÚ	exceptionr5   )r.   r?   rS   rj   rZ   s   &&&& r   rˆ   rˆ   ’   s�   é € Ý<ØÒÜ�lŠl˜H˜:Ó&×&Ð&ð]ñ # 7¯J©J¸ÈTÔR×RÒRñ	 	'ñ 	SøÜô ]Ü�w×ÒØä×ÑÐ@À'Ç,Á,ÐP[×\ð	]üsD   ‚%B§A¨B­A ÁAÁA Á
BÁA Á>BÂBÂBÂBc                ó^  € V P                   P                  4       '       d   R# VP                  4       '       d   V P                   P                  4        R# VP                  4       e,   V P                   P	                  VP                  4       4       R# V P                   P                  R4       R# )zSEvery absorbed caller sees the merged admission's outcome, refusal or cancellation.N)r   Ú	cancelledr{   r�   Úset_exceptionÚ
set_result)rS   rs   s   &&r   r‰   r‰   ¡   sk   € à‡z�z‡�×ÒÙØ‡~�~×ÒØ�
‰
×ÑÖØ	�‰Ó	Ò	%Ø�
‰
× Ñ  §¡Ó!1Ö2à�
‰
×Ñ˜dÖ#r   c                óŠ  € V P                   P                  R/ 4      P                  4        Uu. uF  qP                  NK  	  ppV. V P                   P                  R/ 4      P                  4       OV P                   P                  RR4      O,          pV Uu. uF  q3P                  4       '       d   K  VNK  	  up# u upi u upi )z¶Inputs the reader already returned on that are not committed yet: held bursts, burst commits
and busy inputs released before their commit (``session_ingress._hold_until_committed``).rB   rC   rH   r   )r3   r=   rO   r   )r.   rS   rT   Úfutures   &   r   Ú
_undurabler–   ­   s´   € ð (/×'7Ñ'7×';Ñ';Ð<LÈbÓ'Q×'XÑ'XÔ'ZÓ[Ñ'Z˜e�zŒzÑ'Z€GÐ[Øð B�×!Ñ!×%Ñ%Ð&=¸rÓB×IÑIÓKð BØ×!Ñ!×%Ñ%Ð&;¸RÓ@ðBõ B€Gá!(Ó>¡�v·±·�FˆF¡Ñ>Ð>ùò \ùò ?s   ­B;ÂC Â2C c              ƒ  óì   a "  € \        S RR4      e
   VS n        R# \        S 4      '       g   V! 4       G Rj  x€L
  R# VS n        V 3R lp\        S \        P
                  ! V! 4       4      4       R#  L:5i)ar  Run ``persist()`` once every input a serial reader returned on is committed: a reader that
saves its own receive cursor after the call returns (Buzz) must not advance it past a held burst,
or a restart in the hold window loses it. Inline when nothing is pending; otherwise one tracked
task per adapter, so the reader reads on (a lost cursor write only replays inputs admission
already holds). ``persist`` carries the cursor as of this call; while that task waits, a newer
call replaces it, and the task picks the newest in the same step that saw nothing pending, so
an input that arrives during the write's I/O is never in it.Ú_durable_persistNc               “   ó  <"  €  \        S4      ;p '       d!   \        P                  ! V 4      G R j  x€L
  K3   SP                  P	                  RR 4      pV! 4       G R j  x€L
  R #  L4  SP                  P	                  RR 4      pi ; i L)5i)Nr˜   )r–   r   rP   r3   rƒ   )rT   Úlatestr.   s     €r   ÚlaterÚ+when_returned_inputs_durable.<locals>.laterÆ   sz   øé € ð	DÜ'¨Ó0Ð0�'Ö0Ü—l’l 7Ó+×+Ò+ð 1ð ×%Ñ%×)Ñ)Ð*<¸dÓCˆFÙ‹h�Šñ ,øà×%Ñ%×)Ñ)Ð*<¸dÓC‰FúÙùs7   ƒB…,A( ±A&²A( ¹&BÁB	Á BÁ&A( Á(BÂB)r9   r˜   r–   rt   r   r€   )r.   Úpersistr›   s   f& r   Úwhen_returned_inputs_durablerž   ¶   se   øé € ô ˆwÐ*¨DÓ1Ò=Ø#*ˆÔ ÙÜ�g×ÒÙ‹i�ˆÙØ&€GÔõô ˆ7”G×'Ò'©«Ó0Ö1ñ 	ùs   ƒ4A4·A2¸;A4c                ó  € V P                   P                  R/ 4      P                  VR4      pVeZ   VP                  P	                  4        VP
                  P                  4       ;'       g    VP
                  P                  R4       R# R# )z^``/stop`` / ``/new`` drop a held burst as main dropped its debounce buffer; nothing was ACKed.rB   N)r3   r=   rƒ   r   r{   r   r“   )r.   r?   rS   s   && r   rL   rL   Ð   si   € à×Ñ× Ñ Ð!1°2Ó6×:Ñ:¸;ÈÓM€EØÒØ�‰×ÑÔØ�
‰
�‰Ó×8Ð8˜UŸZ™Z×2Ñ2°4Ó8úñ r   )Ú__doc__r   Údataclassesr   r   Ú	functoolsr   Úloggingr`   Úgateway.platforms.eventr   r   Ú	getLoggerr    rŽ   r	   r0   r6   r:   rE   rV   re   rc   rt   rb   rN   rˆ   r‰   r–   rž   rL   r   r   r   Ú<module>r¦      sš   ðñó ß (Ý Û Û ç =à	×	Ò	˜8Ó	$€ñ ˆeÔ÷1ð 1ó ð1òPò1ò:òvò
ò*2ò:;òò	?òò]ò	$ò?ò2ô49r   