+
    lHàj ã                  ón  a € 0 t $ R t^ RIHt ^ RIt^ RIt^RIHt ]P                  R R l4       t	RR/R R llt
RtR	 R
 lltRt]! 0 Rum4      tR R ltRRRR/R R lltR R ltR R ltR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/R* R+ llt]P                  R, R- l4       tR. R/ lt]! 0 Rvm4      tR1 R2 lt RwR3 R4 llt!R5 R6 lt"RxR8 R9 llt#]! 0 Rym4      t$R: R; lt%R<R0/R= R> llt&R?R7/R@ RA llt'RB RC lt(/ t)RD]*RE&   RF RG lt+R?R7/RH RI llt,/ t-RJ]*RK&   RL RM lt.RNt// t0RD]*RO&   RtRP RQ llt1RR RS lt2R?R7RTR/RU RV llt3RW RX lt4RY RZ lt5R[RR\R]/R^ R_ llt6RtR` Ra llt7/ t8Rb]*Rc&   Rd Re lt9Rf Rg lt:Rh Ri lt;Rj Rk lt<RlRRmR/Rn Ro llt=R?R/Rp Rq llt>Rr Rs lt?R# )za  Session lifecycle: active-session slot leases, finalize/teardown/close, turn interrupt,
WS-orphan reap scheduling, transport-scoped close. Bodies are rebound onto server.py's
globals at install time (method_ctx.bind_module), so they reference server.py globals bare.
)ÚannotationsN)Úbind_modulec               ó   € V ^8„  d   QhRR/# ©é   ÚsessionÚdict© )Úformats   "ÚB/home/ubuntu/.hermes/hermes-agent/tui_gateway/session_lifecycle.pyÚ__annotate__r      s   € ÷ ñ  Tñ ó    c           	   #  óä   "  € ^ RI Hp VP                  4       ;_uu_ 4       q R,          ;_uu_ 4        Vx € RRR4       RRR4       R#   + '       g   i     L; i  + '       g   i     R# ; i5i)zXHold process admission until the history-locked running claim is visible to idle probes.©Ú
retirementÚhistory_lockN)Úhermes_cli.backend_retirementr   Úwork)r   r   Úadmitteds   &  r   Ú_session_turn_admissionr      sB   é € õ 9à	�‰×	Ô	˜h°×(?×(?ØŠ÷ )@×	Ñ	×(?×(?ú×	×	Ð	üs1   ‚A0¡A²A		·A¿
A0Á	AÁAÁA-	Á'	A0r   c               ó    € V ^8„  d   QhRRRR/# )r   ÚnameÚstrr   údict | Noner	   )r
   s   "r   r   r      s   € ÷ ñ ¨ð °{ñ r   c               óä   a a€ ^ RI Hp ^ RIHo SP	                  4       '       g   R# VV 3R lp V! WAR7      pVe   WRR&   VP                  4        V#   \         d    SP                  4        h i ; i)zWReserve before spawning; release only after the worker (including cleanup) has unwound.)Úspawn_context_threadr   Nc                 ób   <€  S! 4        S P                  4        R #   S P                  4        i ; i©N©Úrelease)r   Útargets   €€r   ÚrunÚ _start_session_work.<locals>.run    s&   ø€ ð	!ÙŒHà×ÑÖ øˆJ×ÑÕ ús   ƒ œ.)r   Ú_run_thread)Úagent.memory_providerr   r   r   ÚacquireÚstartÚBaseExceptionr   )r    r   r   r   r!   Úthreadr   s   f$$   @r   Ú_start_session_workr)      si   ù€ å:Ý8à×Ñ×ÒÙö!ðÙ% cÔ5ˆØÒØ%+�MÑ"Ø�‰ŒØˆøÜô Ø×ÑÔØðús   ¯"A ÁA/c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Ú
event_typer   Ú
session_idú
str | NoneÚplatformÚreturnz	list[str]r	   )r
   s   "r   r   r   1   s*   € ÷ ñ ¨ð ¸*ð ÐPZð Ðfoñ r   c           
     ó  € \         P                  ! \        4      ;_uu_ 4        ^ RIHpHpHp V R8X  d$   V! V! V\        V4      R7      4      uuRRR4       # V! W\        V4      R7       RRR4       . #   + '       g   i     . # ; i)zcFire session lifecycle hooks with CLI parity; returns plugin ``on_session_finalize`` user messages.)Úfinalize_sessionÚinvoke_hookÚsession_end_messagesÚon_session_finalize)r,   r.   N)Ú
contextlibÚsuppressÚ	ExceptionÚhermes_cli.lifecycler1   r2   r3   Ú_resolve_agent_platform)r+   r,   r.   r1   r2   r3   s   &&&   r   Ú_notify_session_boundaryr:   1   sp   € ä	×	Ò	œY×	'Õ	'ß\Ñ\ØÐ.Ô.Ù'Ñ(8ÀJÔYpÐqyÓYzÔ({Ó|÷ 
(Ò	'ñ 	�JÔ@WÐX`Ó@aÕb÷	 
(ð
 €I÷ 
(Ö	'ð
 €Iús   £*A5ÁA5Á5B	z8Hermes could not safely reserve this session. Try again.Úws_disconnectc               ó    € V ^8„  d   QhRRRR/# )r   Úlive_session_idr   r/   r   r	   )r
   s   "r   r   r   ?   s   € ÷ 0ñ 0 Sð 0¨Tñ 0r   c                ó
   € RV /# )z»Writer identity for a lease: ``live_session_id`` is half of ``_is_same_writer``. Bot Chat delivery is
admitted by the session authority (gateway/session_bot), never gated on a lease flag.r=   r	   )r=   s   &r   Ú_lease_metadatar?   ?   s   € ð ˜Ð/Ð/r   ÚsurfaceÚtuiÚprofile_homec          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   Úsession_keyr   r=   r@   rB   zstr | Path | Noner/   ztuple[Any, str | None]r	   )r
   s   "r   r   r   E   s4   € ÷ 6ñ 6Øð6Ø*-ð6Ø8;ð6ØSdð6àñ6r   c               ó  €  ^ RI Hp T! Y\        4       T\        V4      \	        T;'       g    R4      P                  4       P                  4       R8H  R7      #   \         d)   p\        P                  RT4       R\        3u Rp?# Rp?ii ; i)é    )Útry_acquire_active_sessionÚ Údesktop)r,   r@   ÚconfigÚregistry_homeÚmetadataÚtrack_livenessz'Failed to claim active session slot: %sN)Úhermes_cli.active_sessionsrG   Ú	_load_cfgr?   r   ÚstripÚlowerr7   ÚloggerÚwarningÚ_SESSION_OWNERSHIP_UNAVAILABLE)rD   r=   r@   rB   rG   Úexcs   &$$$  r   Ú_claim_active_session_slotrV   E   s   € ð6ÝIÙ)Ø"¼I»KÐWcÜ$ _Ó5Ü˜wŸ}˜}¨"Ó-×3Ñ3Ó5×;Ñ;Ó=ÀÑJôLð 	Løô ô 6Ü�‰Ð@À#ÔFð Ô4Ð5Õ5ûð6ús   ‚AA ÁBÁ#BÂ BÂBc               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Úsidr   r   r   Úframer/   ÚNoner	   )r
   s   "r   r   r   X   s.   € ÷ Fñ F ð F¨tð F¸Dð FÀTñ Fr   c           	     óÒ  € VP                  R4      p\        V\        4      '       d   VP                  R4      e   R# \        VP                  R4      ;'       g    R4      pV'       d*   \        VP                  R4      ;'       g    R4      V8w  d   R# ^ RIHp T! RVP                  R4      ;'       g    T  2T\        VP                  R	4      ;'       g    R
4      RR7      VR&   R# )u›  Adopt the parent's registry slot as an INERT token on a compute-host child.

An isolated turn runs in the compute-host CHILD process. The parent dashboard already
claimed the session's active-session lease before routing the turn here, but the child's
freshly built session record never carried it â€” so ``_admit_prompt_turn`` re-claimed from
the child's pid and was fenced out by the parent's own entry (``_is_same_writer`` requires
same pid AND same live_session_id): every isolated turn failed with "Session ... already
has a live owner" (#101416). The slot is real and owned upstream, so the child must
neither claim a second one nor be able to release/transfer the parent's: the token is
``enabled=False`` â€” ``release()`` is a no-op and ``transfer_active_session`` only retargets
the token locally, so a compression rotation A->B inside the child never reaches the
registry (the parent re-anchors its real lease from the reported ``session_key``, see
``_compute_host_adopt_frame_meta``). NOT ``released=True``: a released token makes the
transfer fall through to a real registry claim under the child pid.

Only installed when the frame's ``active_session_lease`` vouch names THIS stored session
id â€” a parent lease still keyed on a pre-rotation id must not authorize its continuation.
Anything else keeps the legacy behaviour â€” the child claims for itself and any ownership
conflict fails CLOSED with the visible refusal.
Úactive_session_leaseNrD   rH   r,   )ÚActiveSessionLeasez	borrowed:Úlease_idÚsourcerI   F)r^   r,   r@   Úenabled)ÚgetÚ
isinstancer   r   rN   r]   )rX   r   rY   ÚvouchÚkeyr]   s   &&&   r   Ú_install_borrowed_leasere   X   s½   € ð* �I‰IÐ,Ó-€EÜ�eœT×"Ò" g§k¡kÐ2HÓ&IÒ&UÙÜ
ˆg�k‰k˜-Ó(×.Ð.¨BÓ
/€Cß”#�e—i‘i Ó-×3Ð3°Ó4¸Ô;ÙÝ=Ù&8Ø˜UŸY™Y zÓ2×9Ð9°cÐ:Ð;ÈÜ�E—I‘I˜hÓ'×4Ð4¨9Ó5¸uô'F€GÐ"Ó#r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   rX   r   r   r   r/   r-   r	   )r
   s   "r   r   r   y   s!   € ÷ ñ  Sð °4ð ¸Jñ r   c                ód  € \        V4      ;pe   V# VP                  R4      e   R# \        VP                  R4      ;'       g    R4      p\        W0\	        V4      VP                  R4      R7      w  rEVf   \        W4       R# ^ RIHp \        VRR4      V8X  d   \        WV4      '       d   R# V# )	a•  Claim this session's cap slot on its first real turn; None when ok. session.create/resume deliberately
do NOT claim: tile paints, reconnect-resumes and abandoned drafts would hold invisible slots (no DB row)
that starve the messaging gateway sharing the cap. Anything holding a slot must be user-visible. An
inert borrowed token (see _install_borrowed_lease) also lands here: present = slot held upstream.Nr\   rD   rH   rB   ©r=   r@   rB   )ÚSESSION_NOT_OWNEDÚreason)
Ú_canonical_ledger_refusalra   r   rV   Ú_session_sourceÚ_attach_leaserN   ri   ÚgetattrÚ!_take_over_detached_runtime_lease)rX   r   Ú	canonicalrd   ÚleaseÚlimit_messageri   s   &&     r   Ú_ensure_active_session_slotrs   y   s­   € ô
 /¨wÓ7Ð7ˆ	ÒDØÐØ‡{�{Ð)Ó*Ò6ÙÜ
ˆg�k‰k˜-Ó(×.Ð.¨BÓ
/€CÜ5Ø¬/¸'Ó*BÐQX×Q\ÑQ\Ð]kÓQlônÑ€EàÒÜ�gÔ%ÙÝ<Üˆ}˜h¨Ó-Ð1BÔBÔGhÐilÐwz×G{ÒG{ÙØÐr   z»SELECT status FROM session_admissions WHERE target_session_id=? AND status!='terminal'
    UNION ALL SELECT status FROM worker_executions WHERE session_id=? AND status!='terminal' LIMIT 1c               ó$   € V ^8„  d   QhRRRRRR/# )r   r,   r   Ú
end_reasonr/   Úboolr	   )r
   s   "r   r   r   ’   s"   € ÷ ñ ¨Cð È#ð ÐRVñ r   c                ó¸   a aaa€ \        S RR4      pVf   S P                  SS4       R# V VVV3R lpV! V4      '       d   R# \        P                  RSS4       R# )a�  End *session_id*'s row unless the gateway's durable ledger still holds work for it; True when
the row may end (ended now, or already ended). The check and the stamp share one write txn.

A viewer process (a dashboard, a second Desktop window) runs this reaper for a session the
owning gateway is still executing; stamping it ended mid-turn made the owner treat its own live
route as stale (#54878) and replace the conversation (#140642). The ledger names a local session
by its logical id (the row's ``chat_id``), so the physical id, the key and that id are checked: a
``local-`` id, or the lineage owner its receipt names (an adopted conversation keeps its legacy id).Ú_execute_writeNTc                ó.  <€ V P                  R S34      P                  4       pS\        S;'       g    R4      0pVeS   \        V^ ,          ;'       g    R4      P                  R4      '       d"   VP	                  \        V^ ,          4      4       ^ RIHp VP	                  V! V S4      4       \        RV4       F-  pV P                  \        WD34      P                  4       f   K,   R# 	  SP                  V R\        P                  4       SS3SS4       R# )z'SELECT chat_id FROM sessions WHERE id=?rH   Nzlocal-)Úlocal_lineage_ownerFzRUPDATE sessions SET ended_at = ?, end_reason = ? WHERE id = ? AND ended_at IS NULLT)ÚexecuteÚfetchoner   Ú
startswithÚaddÚhermes_state_localrz   ÚfilterÚ_CANONICAL_PENDING_SQLÚ_end_and_bumpÚtime)	ÚconnÚrowÚidsrz   rX   Údbru   r,   rD   s	   &    €€€€r   ÚwriteÚ&_end_unless_ledger_busy.<locals>.write    sã   ø€ Ø�l‰lÐDÀzÀmÓT×]Ñ]Ó_ˆØœ3˜{×0Ð0¨bÓ1Ð2ˆØŠ?œs 3 q¥6§< <¨RÓ0×;Ñ;¸H×EÒEØ�G‰G”C˜˜A�“KÔ Ý:Ø�‰Ñ# D¨*Ó5Ô6Ü˜$ Ö$ˆCØ�|‰|Ô2°S°JÓ?×HÑHÓJÔVÚñ %ð 	×Ñ˜ÐsÜŸ)™)›+ z°:Ð>À
ÈJô	Xár   zJPreserving session %s during %s: the gateway's ledger still holds its turnF)rn   Úend_sessionrR   Úinfo)r‡   r,   rD   ru   Úexecute_writerˆ   s   ffff  r   Ú_end_unless_ledger_busyr�   ’   s[   û€ ô ˜BÐ 0°$Ó7€MØÒØ
�‰�z :Ô.Ù÷ð ñ �U×ÒÙÜ
‡K�KÐ\Ð^hÐjtÔuÙr   c               ó   € V ^8„  d   QhRR/# r   r	   )r
   s   "r   r   r   ´   s   € ÷ "ñ " tñ "r   c                óÚ  € ^ RI p^ RIHpHpHp \        V P                  R4      ;'       g    R4      pV'       g   R#  \        V 4      ;_uu_ 4       p\        VRR4      pVf    RRR4       R# V! 4       ;_uu_ 4       p\        \        VP                  \        WU34      4      R4      p	RRR4       RRR4       X	f   R# \        P#                  R	YY^ ,          4       T! R
T RT	^ ,          R8X  d   RMR R2T4      p
T	^ ,          T
n        T
#   + '       g   i     Lk; i  + '       g   i     Lv; i  TP                   d)    \        P                  RTRR7       T! \         T4      u # i ; i)a(  Refusal when the gateway's durable ledger still holds work for this stored session, else None.

The registry lease only fences other legacy backends. A session a gateway once owned can carry
an ``unknown`` admission (outcome lost across an owner restart: never replayed, only Discard
resolves it), queued input or a running worker; a legacy turn would run past that barrier
and write the transcript beside the canonical FIFO. Checked on every turn, not only at the
first claim, because a gateway may admit work while this backend still holds its lease.N)ÚActiveSessionRefusalÚ SESSION_COORDINATION_UNAVAILABLEri   rD   rH   Ú	_read_ctxz#canonical ledger read failed for %sT©Úexc_infoz;Refusing legacy turn for %s: canonical ledger holds %s workzSession z has Úunknownzoutcome-unknownÚpendingz“ work in the gateway's durable queue. Resume it through the gateway (hermes chat --resume, Desktop or the TUI) to resolve it; nothing was run here.)Úsqlite3rN   r�   r‘   ri   r   ra   Ú_session_dbrn   ÚnextÚiterr{   r�   ÚErrorrR   rS   rT   r‹   Úledger_status)r   r—   r�   r‘   ri   rd   r‡   Úread_ctxr„   r…   Úrefusals   &          r   rk   rk   ´   sK  € ó ÷Sñ Sä
ˆg�k‰k˜-Ó(×.Ð.¨BÓ
/€CßÙð	fÜ˜×!Ô! RÜ˜r ;°Ó5ˆHØÒØ÷ "Ñ!ñ —”˜tÜœ4 §¡Ô-CÀcÀZÓ PÓQÐSWÓX�÷ ÷	 "ð ‚{ÙÜ
‡K�KÐMÈsÐXYÕTZÔ[Ù"Ø
�3�%�u°#°aµ&¸IÔ2EÑ.È9ÐUð V,ð 	,à->ó@€Gð   �F€GÔØ€N÷ —ú÷	 "×!ûð �=‰=ô fÜ�‰Ð<¸cÈDˆÔQÙ#Ô$BÐDdÓeÒeðfúsS   ¾D1 ÁDÁ$D1 Á.DÁ=+D	Â(DÂ0D1 ÄDÄDÄD.	Ä)D1 Ä.D1 Ä16E*Å)E*c               ó    € V ^8„  d   QhRRRR/# ©r   r   r   r/   rZ   r	   )r
   s   "r   r   r   Ù   s   € ÷ +ñ +˜4ð +¨4ñ +r   c                ó2   € WR &   V P                  RR4       R# )r\   Ú_lease_taken_overN)Úpop)r   rq   s   &&r   rm   rm   Ù   s   € Ø&+Ð"Ñ#Ø‡K�KÐ# TÖ*r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r   rd   r   r/   ztuple[str, dict] | Noner	   )r
   s   "r   r   r   Þ   s"   € ÷ 
ñ 
 Dð 
¨sð 
Ð7Nñ 
r   c                ó®  € \         P                  4        F¼  w  r#W0J ga   VP                  R4      '       gJ   \        VP                  R4      ;'       g    R4      V8w  g!   \	        W0P                  R4      4      '       g   Kl  VP                  R4      pVf   Kƒ  VP
                  '       d   K—  \        VP                  R4      4      '       g   K¹  W#3u # 	  R# )z†A sibling runtime of ``session`` (same key, same profile) holding an unreleased lease with no client.
Caller holds ``_sessions_lock``.Ú
_finalizedrD   rH   rB   r\   NÚ	transport)Ú	_sessionsÚitemsra   r   Ú_live_profile_matchesÚreleasedÚ_transport_is_dead)r   rd   Ú	other_sidÚotherrq   s   &&   r   Ú_detached_lease_holderr¯   Þ   s¢   € ô &ŸO™OÖ-Ñˆ	ØÓ §	¡	¨,× 7Ò 7¼3¸u¿y¹yÈÓ?W×?]Ð?]Ð[]Ó;^ÐbeÔ;eÜ,¨U·K±KÀÓ4O×PÒPÙØ—	‘	Ð0Ó1ˆØÔ U§^§^¢^Ô8JÈ5Ï9É9ÐU`ÓKa×8bÔ8bØÐ#Ò#ñ .ñ r   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   rX   r   r   r   rd   r/   rv   r	   )r
   s   "r   r   r   ë   s(   € ÷ ñ ¨3ð ¸ð ÀCð ÈDñ r   c                ó8  € ^ RI Hp \        ;_uu_ 4        \        ;_uu_ 4        \	        W4      ;pf    RRR4       RRR4       R# Vw  rVVR,          pV! Wr\        V 4      R7      '       g    RRR4       RRR4       R# VR RVR&   \        W4       RRR4       RRR4       \        P                  RWX4        \        VXR	V  2R
7       R#   + '       g   i     LC; i  + '       g   i     LN; i  \         d    \        P                  RT4        R# i ; i)u°  Hand a detached sibling runtime's lease for ``key`` to ``session``; True when it now owns the slot.

Lease identity is (pid, live_session_id), so a client that reconnects under a NEW runtime â€” Desktop
restoring a chat after a renderer crash, a reload during the client-gone settle window (4009 fences
``session.resume``) â€” is a "different writer" of its own chat and was refused ``SESSION_NOT_OWNED`` until
the old runtime's reap released the lease (up to grace + activity-stale + interrupt polls). The user IS the
owner: the old runtime is in THIS process and has no client, so the lease moves and its turn is asked to
stop (hard interrupt, honoured at the agent's next check â€” the same best-effort stop the reaper relies on).
A live foreign pid, a sibling that still has a client, or a same-id runtime of another profile keeps
refusing â€” cross-process, multi-window and cross-profile (#100029) exclusivity are untouched. See #104691.
©Útransfer_active_sessionNFr\   ©r,   rL   Tr¢   z:Session %s took over lease for %s from detached runtime %szlease-takeover-©Ú
request_idz&lease-takeover interrupt failed sid=%s)rN   r³   Ú_session_resume_lockÚ_sessions_lockr¯   r?   rm   rR   r‹   Ú_interrupt_session_turnr7   Ú	exception)rX   r   rd   r³   Úfoundr­   r®   rq   s   &&&     r   ro   ro   ë   só   € õ Cß	Ö	Ÿ~ž~Ü+¨GÓ9Ð9ˆEÒBØ÷  .×	Ñ	ð !Ñˆ	ØÐ,Õ-ˆÙ& uÄÐWZÓG[×\Ó\Ø÷  .×	Ñ	ð Ð(Ð)Ø%)ˆÐ!Ñ"Ü�gÔ%÷  .×	ô ‡K�KÐLÈcÐXaÔbðNÜ 	¨5¸ÈsÈeÐ=TÕUñ ÷  .Ÿ~ú×	×	ûô ô NÜ×ÑÐAÀ9ÕMÙðNúsK   •C!¤C	µC!Á'C	Á.C!Â C	ÂC!Â;C4 ÃCÃC!Ã!C1	Ã4!DÄDc               ó    € V ^8„  d   QhRRRR/# )r   ÚattemptsÚintr/   zException | Noner	   )r
   s   "r   r   r   
  s   € ÷ ñ ˜3ð Ð'7ñ r   c                óà   € \        V 4       F  p V! 4         R# 	  X#   \         dE   pTpT^,           T 8  d*   \        P                  RT^,           ,          4        Rp?KV   Rp?K\  Rp?ii ; i)z‘Call ``fn`` up to ``attempts`` times (50ms*n backoff: registry writes contend across processes); last
exception when every try failed, else None.Nçš™™™™™©?)Úranger7   rƒ   Úsleep)r½   ÚfnÚattemptrU   Ú
last_errors   &&   r   Ú_lease_retryrÆ   
  sg   € ô ˜–?ˆð	1ÙŒDÚñ #ð Ðøô	 ô 	1ØˆJØ˜�{˜XÔ%Ü—
‘
˜4 7¨Q¥;Õ/×0Ò0õ &ûð	1ús   �žA-©3A(Á(A-c               ó    € V ^8„  d   QhRRRR/# ©r   r   r   r/   rv   r	   )r
   s   "r   r   r     s   € ÷ ñ ¨+ð ¸$ñ r   c                ól  a€ V '       d   V P                  R4      MRoSf   R# \        \        SRR4      '       d   ^M^V3R l4      ;pe   \        P	                  RVR7       R# \        SR	R4      '       g   \        SR
R4      '       d   R# V P                  R4      SJ d   V P                  RR4       R# )zVRelease the session's lease (liveness-tracked leases get 3 tries); True when released.r\   NTrM   Fc                 ó$   <€ S P                  4       # r   r   )rq   s   €r   Ú<lambda>Ú._release_active_session_slot.<locals>.<lambda>  s   ø€ ÐY^×YfÑYfÔYhr   z%Failed to release active session slotr“   r«   r`   )ra   rÆ   rn   rR   rS   r£   )r   Úerrrq   s   & @r   Ú_release_active_session_slotrÎ     sš   ø€ ç3:ˆG�K‰KÐ.Ô/À€EØ‚}ÙÜ¤¨Ð0@À%×!HÒ!H™AÈaÔQhÓiÐiˆÒvÜ�‰Ð>ÈˆÔMÙÜ�E˜: t×,Ò,´G¸EÀ9Èd×4SÒ4SÙØ‡{�{Ð)Ó*¨eÓ3Ø�‰Ð*¨DÔ1Ùr   c               ó    € V ^8„  d   QhRRRR/# r    r	   )r
   s   "r   r   r   '  s   € ÷ .ñ .¨Dð .°Tñ .r   c                óL   € ^ RI Hp \        V 4      V8X  d   \        V 4       R# R# )uø  End-of-turn release for hosted room member sessions (``source=bot_room``) only.

A hosted room turn is serialized by the room driver's lease, not by this process, so the member
profile's ``bot_room`` slot is needed only while a turn is in flight. Holding it for the life of
the live session (which no reaper ever ends: room sessions have no client transport) locked every
other room worker sharing the home â€” messaging gateway + Desktop ``serve`` â€” out of that member
with ``Refused active session â€¦ already held by pid=â€¦`` until this process exited (#106847).
Call under ``history_lock`` next to ``running = False`` so the next admission never observes the
stale lease and then runs lease-less; ``_admit_prompt_turn`` re-claims on the following turn.
)ÚROOM_SESSION_SOURCEN)Útui_gateway.hosted_room_driverrÑ   rl   rÎ   )r   rÑ   s   & r   Ú_release_hosted_room_turn_slotrÓ   '  s#   € õ CÜ�wÓÐ#6Ô6Ü$ WÖ-ñ 7r   Úexcludec               ó   € V ^8„  d   QhRR/# )r   r/   zset[str]r	   )r
   s   "r   r   r   7  s   € ÷ 9ñ 9¨Hñ 9r   c                ó8  € \         ;_uu_ 4        \        P                  4        Uu0 uF6  pVP                  R4      ;pf   K  W Jg   K!  \	        VP
                  4      kK8  	  up\        \        4      ,          uuRRR4       # u upi   + '       g   i     R# ; i)u®   Snapshot leases still backed by this process's live session records (plus leases deferred past a
close for an unsettled isolated turn â€” still ours until the child settles).r\   N)r¸   r¨   Úvaluesra   r   r^   ÚsetÚ_deferred_active_session_leases)rÔ   r   rq   s   $  r   Ú_own_live_lease_idsrÚ   7  sy   € ÷ 
ŽÜ3<×3CÑ3CÔ3Eó Ñ3E¨Ø$Ÿ[™[Ð)?Ó@Ð@�Eô $ØRWÐRfô $”�E—N‘NÖ#Ñ3Eñ äÔ7Ó8õ9÷ 
Šùò÷ 
�ˆús(   �B¦BÁBÁ	BÁ"BÂBÂB	c               ó    € V ^8„  d   QhRRRR/# )r   r,   r   r   r   r	   )r
   s   "r   r   r   A  s   € ÷ !6ñ !6¨3ð !6¸ñ !6r   c           	   #  ó  a aaaaaa	a
"  € SP                  R4      o ^ RIHoHo	 \        P                  ! 4       o
. o\        SR7      oR TTTTT	TT T
3R llp\        ^T4      ;pe.   S
P                  4        \
        P                  R	S T4       Rx € R#  S^ ,          x € S
P                  4        SeA   \        SR
R4      '       d,   SP                  R4      SJ d   SP                  RR4       R# R# R# R#   \         d'   p\
        P                  RS T4       Rx €  Rp?R# Rp?ii ; i  S
P                  4        Se>   \        SR
R4      '       d*   SP                  R4      SJ d   SP                  RR4       i i i i ; i5i)zÙRelease this runtime and lock sibling ownership through the DB write. Yields True (another runtime owns
the lifecycle -> preserve) when the guard can't be loaded/entered in 3 tries: unknown ownership never ends a row.r\   )Úactive_session_liveness_guardÚ%release_active_session_liveness_guardzHFailed to load active session ownership guard; preserving session %s: %sTN)rÔ   c               ó   € V ^8„  d   QhRR/# ©r   r/   rZ   r	   )r
   s   "r   r   Ú0_other_runtime_lease_guard.<locals>.__annotate__O  s   € ÷ 1ñ 1�Dñ 1r   c                 óÌ   <€ SP                  4        Se    \        SRR4      '       d   S! SSSR7      p MS! SSP                  R4      SR7      p SP                  V 4      .SR&   R # )Nr`   F)Úown_live_lease_idsrB   )rK   rã   :NNN)Úclosern   ra   Úenter_context)	ÚguardÚactiverÝ   rq   rã   rÞ   r   r,   Ústacks	    €€€€€€€€r   Ú_enterÚ*_other_runtime_lease_guard.<locals>._enterO  sb   ø€ Ø�‰ŒØÒ¤¨°	¸5×!AÒ!AÙ9¸%ÀÐ`rÔs‰Eá1Ø¨'¯+©+°nÓ*EÐZlônˆEà×(Ñ(¨Ó/Ð0ˆˆq‹	r   zBFailed to inspect active session leases; preserving session %s: %sr«   F)ra   rN   rÝ   rÞ   r7   rR   rS   r5   Ú	ExitStackrÚ   rÆ   rä   rn   r£   )r,   r   rU   ré   rÅ   rç   rÝ   rq   rã   rÞ   rè   s   ff   @@@@@@r   Ú_other_runtime_lease_guardrì   @  sT  ÿé € ð �K‰KÐ.Ó/€Eðßsô
 × Ò Ó"€EØ€FÜ,°UÔ;Ð÷1÷ 1ô # 1 fÓ-Ð-ˆ
Ò:Ø�‰ŒÜ�‰Ð[Ð]gÐisÔtØŠ
Ùð6Ø�Q�iŠà�‰ŒØÒ¤¨°
¸E×!BÒ!BÀwÇ{Á{ÐSiÓGjÐnsÓGsØ�K‰KÐ.°Ö5ñ HtÑ!BÑøô5 ô Ü�‰ÐaÐcmÐorÔsØŠ
Ýûðûð2 	�‰ŒØÒ¤¨°
¸E×!BÒ!BÀwÇ{Á{ÐSiÓGjÐnsÓGsØ�K‰KÐ.°Õ5ð HtÐ!BÐüsH   ŠF�C7 ¥A0FÂD+ Â!AFÃ7D(ÄD#ÄFÄ#D(Ä(FÄ+AE>Å>Fc               ó(   € V ^8„  d   QhRRRRRRRR/# )r   rX   r   r   r   Únew_session_idr/   rv   r	   )r
   s   "r   r   r   e  s)   € ÷ ñ  sð °Tð Ècð ÐVZñ r   c               ó@  € V'       g   R # VP                  R4      pVf   R#  ^ RIHp V! W2\        V 4      R7      '       d   R#  \        VRR 4      '       d   R # \        W \        V4      VP                  R	4      R
7      w  rVVf"   V'       d   \
        P                  RWV4       R # VP                  RR4      ;pe6   \        ^VP                  4      ;p'       d   \
        P                  RVR7       WQR&   R#   \         d    \
        P                  RRR7        L×i ; i)Fr\   NTr²   r´   z&Failed to transfer active session slotr“   rM   rB   rh   z_Compression session lease re-anchor failed (kept old lease): sid=%s new_session_id=%s reason=%sz+Failed to release stale active session slot)ra   rN   r³   r?   r7   rR   Údebugrn   rV   rl   rS   r£   rÆ   r   )	rX   r   rî   rq   r³   Ú	new_leaserr   ÚoldrÍ   s	   &&$      r   Ú_transfer_active_session_slotró   e  s  € ßÙØ�K‰KÐ.Ó/€EØ‚}ÙðNÝFÙ" 5ÌoÐ^aÓNb×cÓcÙð dô ˆuÐ&¨×.Ò.Ùô  :Ø´_ÀWÓ5MÐ\c×\gÑ\gÐhvÓ\wô yÑ€IàÒßÜ�N‰NÐ|Ø°ô?áØ�{‰{Ð1°4Ó8Ð8ˆÒEÔR^Ð_`Ðbe×bmÑbmÓRnÐKnÈ3ÖKnÜ�‰ÐBÈSˆÔQØ&/Ð"Ñ#Ùøô# ô NÜ�‰Ð=ÈˆÖMðNús   £C8 Ã8"DÄDrH   c               ó    € V ^8„  d   QhRRRR/# )r   r_   r   r/   rv   r	   )r
   s   "r   r   r   Œ  s   € ÷ ñ  Sð ¨Tñ r   c                ó²   € T ;'       g    RP                  4       P                  4       pV\        9   d   R#  ^ RIHp V! V4       R#   \
         d     R# i ; i)zÜTrue when ``source`` resolves to a gateway ``Platform`` (enum member or plugin via ``Platform._missing_``, so
new platforms are covered automatically); self-owned Platform members (local/webhook/api_server) are excluded.rH   F)ÚPlatformT)rP   rQ   Ú_NON_GATEWAY_SOURCESÚgateway.configrö   r7   )r_   Úsrcrö   s   &  r   Ú_is_gateway_owned_sourcerú   Œ  sQ   € ð �<ˆ<�R×
Ñ
Ó
 ×
&Ñ
&Ó
(€CØ
Ô"Ô"ÙðÝ+Ù�ŒÙøÜô Úðús   ·A ÁAÁAc               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r   Úsid_hintr   r/   r	   )r
   s   "r   r   r   š  s!   € ÷ ñ  ð °ð ¸Sñ r   c           	     óš  a € \        T;'       g    S P                  R4      ;'       g    R4      pV'       gm   \        P                  ! \        4      ;_uu_ 4        \
        ;_uu_ 4        \        V 3R l\        P                  4        4       R4      pRRR4       RRR4       V# V#   + '       g   i     L; i  + '       g   i     T# ; i)zHLive UI sid for ``session``: hint, stamped ``_sid``, else registry scan.Ú_sidrH   c              3  ó<   <"  € T F  w  rVSJ g   K  Vx € K  	  R # 5ir   r	   )Ú.0Úcand_sidÚcandr   s   &  €r   Ú	<genexpr>Ú%_lifecycle_own_sid.<locals>.<genexpr>Ÿ  s    øé € Ð`Ñ;L©¨ÐPTÐX_ÐP_ŸHšHÓ;Lùs   ƒ
’
N)	r   ra   r5   r6   r7   r¸   r™   r¨   r©   )r   rü   Úown_sids   f& r   Ú_lifecycle_own_sidr  š  s}   ø€ ä�(×7Ð7˜gŸk™k¨&Ó1×7Ð7°RÓ8€GßÜ× Ò ¤×+Õ+¯^®^ÜÔ`¼9¿?¹?Ô;LÓ`ÐbdÓeˆG÷ .<×+à€Nˆ7€N÷ .<¯^ú×+Ö+à€Nús$   ÁB9Á))B&	ÂB9Â&B6Â1B9Â9C
	c               ó    € V ^8„  d   QhRRRR/# r    r	   )r
   s   "r   r   r   £  s   € ÷ eñ e $ð e¨4ñ er   c                óæ   €  ^ RI Hp V P                  R4      ;p'       d   VP                  V4       R# R#   \         d0    \
        P                  ! \        4      P                  RRR7        R# i ; i)zbA per-session unlock ends with the session that made it; siblings in the same profile keep theirs.)Úunlockrþ   z(vault manager lock on session end failedTr“   N)	Úagent.vault_backendsr	  ra   Úrelease_sessionr7   ÚloggingÚ	getLoggerÚ__name__rð   )r   r	  rX   s   &  r   Ú_lock_vault_managersr  £  sc   € ðeÝ/à—+‘+˜fÓ%Ð%ˆ3Ö%Ø×"Ñ" 3Ö'ñ &øäô eÜ×Òœ(Ó#×)Ñ)Ð*TÐ_cÐ)×dðeús   ‚6 ¡6 ¶6A0Á/A0Ú	tui_closec               ó$   € V ^8„  d   QhRRRRRR/# ©r   r   r   ru   r   r/   rZ   r	   )r
   s   "r   r   r   ®  s&   € ÷ oñ o˜{ð o¸ð oÈdñ or   c                óJ  € V '       d   V P                  R4      '       d   R# RV R&   \        V 4       V P                  R4      ;pe,   VP                  4       '       g   RV R&   VP                  4        V\        9   ;'       d+    \        V 4      P                  4       P                  4       R8H  pV'       g   \        V 4       V P                  R4      ;pe   VP                  4        V P                  R	4      pV P                  R
4      ;'       g    \        P                  ! 4       ;_uu_ 4        \        V P                  R. 4      4      pRRR4       \        VR4      '       dR   \        VRR4      ;p'       d=   \        P                  ! \        4      ;_uu_ 4        VP!                  V4       RRR4       \#        V 4      ;_uu_ 4        Ve…   \        P                  ! \        4      ;_uu_ 4        ^ RIHp T! RRR\        VRR4      ;'       g    V P                  RR4      \        VRR4      \        VRR4      ;'       g    RR7       RRR4       VeW   X'       dO   \        VR4      '       d=   \        P                  ! \        4      ;_uu_ 4        VP)                  V4       RRR4       RRR4       V P                  R4      p	\        VRR4      ;'       g    T	p
\+        RV
\        V 4      4      ;'       g    . V R&   V'       d   V
'       g   \        V 4       V'       d   V
'       d   \-        W 4      M-\        P                  ! \/        V P                  R4      4      4      pT;_uu_ 4       pV'       * pV'       d   \0        P3                  RW¡4       V
'       d­   \        P                  ! \        4      ;_uu_ 4        \5        V 4      ;_uu_ 4       pVeb   \7        VP9                  V
4      ;'       g    / P                  RR4      4      '       d   RpM$V'       d   V'       g   \;        WêW‘4      '       g   RpRRR4       RRR4       RRR4       Ve   V'       g	   X'       g   RVn        \        P                  ! \        4      ;_uu_ 4        ^ RIH p T! X'       d   \C        T	;'       g    R4      MR\E        V 4      VR 7       RRR4       X'       dK   V	'       dC   \        P                  ! \        4      ;_uu_ 4        ^ R!I#H$p V! \C        V	4      4       RRR4       VeA   \        P                  ! \        4      ;_uu_ 4        ^ R"I%H&p V! VR#V R$2R%R&7       RRR4       \        P                  ! \        4      ;_uu_ 4        V P                  R'4      ;p'       d   VPO                  4        RRR4       R#   + '       g   i     ELv; i  + '       g   i     EL'; i  + '       g   i     ELŸ; i  + '       g   i     ELY; i  + '       g   i     ELe; i  + '       g   i     ELî; i  + '       g   i     ELú; i  + '       g   i     EL; i  + '       g   i     EL�; i  + '       g   i     EL_; i  + '       g   i     EL/; i  + '       g   i     R# ; i)(z”Best-effort finalize hook + memory commit; mirrors the CLI exit path so a force-quit mid-turn (double
Ctrl-C, terminal close, SIGHUP) loses nothing.r¦   NTÚresume_history_readyzsession resume cancelledÚresume_history_errorrI   Ú_notif_stopÚagentr   ÚhistoryÚ_persist_sessionÚ_session_messages©r2   Úon_session_endFr,   rD   rH   Úmodelr•   r.   rA   )Ú	completedÚinterruptedr,   r  r.   Úcommit_memory_sessionr4   Ú	_end_msgsr¢   zEPreserving session %s during %s: another backend owns an active leaser_   ©Úinterrupt_for_session)rD   Úorigin_ui_session_idrj   )Úclear_session©Ú&cancel_background_review_for_live_turnzsession ended (Ú)zsession ended©ÚmessageÚtool_reasonÚslash_worker)(ra   r  Úis_setrØ   Ú_AUTOMATIC_SESSION_END_REASONSrl   rP   rQ   rÎ   r5   ÚnullcontextÚlistÚhasattrrn   r6   r7   r  Ú_session_profile_runtime_scoper8   r2   r   r:   rì   rv   rR   r‹   r˜   rú   Úget_sessionr�   Ú_end_session_on_closeÚtools.async_delegationr#  r   r  Útools.approvalr%  Úagent.background_reviewr'  rä   )r   ru   Úhistory_readyÚ_desktop_automatic_cleanupÚ
stop_eventr  r  Úsnapshotr2   rD   r,   Ú_lifecycle_guardÚ_other_runtime_owns_lifecycleÚ_tui_owns_lifecycler‡   r#  r%  r'  Úworkers   &&                 r   Ú_finalize_sessionr@  ®  sÓ  € ÷ �g—k‘k ,×/Ò/ÙØ €GˆLÑÜ˜Ô!Ø Ÿ™Ð%;Ó<Ð<ˆÒIÐR_×RfÑRf×RhÒRhØ*DˆÐ&Ñ'Ø×ÑÔàÔ4Ñ4×nÐn¼ÈÓ9Q×9WÑ9WÓ9Y×9_Ñ9_Ó9aÐenÑ9nð ÷ &Ü$ WÔ-Ø—k‘k -Ó0Ð0ˆ
Ò=Ø�‰ÔØ�K‰K˜Ó €EØ
�+‰+�nÓ
%×
AÐ
A¬×)?Ò)?Ó)A×
AÑ
AÜ�w—{‘{ 9¨bÓ1Ó2ˆ÷ Bô
 ˆuÐ(×)Ò)¼7À5ÐJ]Ð_cÓ;dÐ/d¨xÖ/dÜ× Ò ¤×+Õ+Ø×"Ñ" 8Ô,÷ ,ô 
(¨×	0Õ	0ØÒÜ×$Ò$¤Y×/Õ/Ý<ÙØ$°À4Ü& u¨l¸DÓA×cÐcÀWÇ[Á[ÐQ^Ð`bÓEcÜ! %¨°)Ó<ÄwÈuÐV`ÐbfÓGg×GpÐGpÐkpõr÷ 0ð Ò§¬W°UÐ<S×-TÒ-TÜ×$Ò$¤Y×/Õ/Ø×+Ñ+¨GÔ4÷ 0÷ 
1ð —+‘+˜mÓ,€KÜ˜ ¨dÓ3×BÐB°{€Jä3Ð4IÈ:ÔWfÐgnÓWoÓp×vÐvÐtv€GˆKÑ÷ "¯*Ü$ WÔ-÷ 6¿*ô 3°:ÔGä'×3Ò3´D¸¿¹ÐEXÓ9YÓ4ZÓ[ð ÷ 
Ñ	Ð:Ø"?Ô?Ðß(Ü�K‰KÐ_ÐakÔxßä×$Ò$¤Y×/Õ/´¸W×1EÔ1EÈØ’>ô 0°·±À
Ó1K×1QÐ1QÈr×0VÑ0VÐW_ÐacÓ0d×eÒeØ.3Ñ+ß,×5Oô
  7°rÀ{×_Ò_Ø27Ð/÷ 2F×/÷ 
ð* Ò×8×@SØ&+ˆÔ#ô 
×	Ò	œY×	'Õ	'Ý@Ùß2Eœ˜K×-Ð-¨2Ô.È2Ü!3°GÓ!<ÀZõ	Q÷ 
(÷ Ÿ{Ü× Ò ¤×+Õ+Ý4Ùœ#˜kÓ*Ô+÷ ,ð ÒÜ× Ò ¤×+Õ+ÝVÙ2Ø °°¸AÐ>ÈOõ]÷ ,ô
 
×	Ò	œY×	'Õ	'Ø—[‘[ Ó0Ð0ˆ6Ö0Ø�L‰LŒN÷ 
(Ñ	'÷w B×
AÐ
Aú÷ ,×+Ð+ú÷ 0×/Ð/ú÷ 0×/Ð/ú÷ 
1×	0Ð	0ú÷> 2F×1EÐ1Eú×/×/Ð/ú÷ 
×	Ð	ú÷2 
(×	'Ð	'ú÷ ,×+Ð+ú÷ ,×+Ð+ú÷
 
(×	'Ð	'úsñ   Ä,V5ÆW	Ç'XÇ-AW	È?W	ÉXÉ4XÊW1	Ê!XÍ*-YÎ"YÎ:X-	Ï!XÏ0XÐ
XÐXÐ XÐ4X-	Ð<YÒ	YÒ(YÓ;Y)ÕY=Ö*ZÖ5W	×	W	×W.×(	X×1X×<	XØX	ØX*Ø$	X-	Ø-X>Ø8	YÙY	ÙY&	Ù)Y:	Ù=Z	ÚZ"	c               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r   ru   r   r/   rZ   r	   )r
   s   "r   r   r   %  s&   € ÷ Jñ J¨ð J¸3ð JÀ4ñ Jr   c                ó   € V\         9  d   R#  \        RR\        V P                  R4      ;'       g    R4      R\        V P                  R4      ;'       g    R4      RV/4       R#   \         d    \
        P                  R	R
R7        R# i ; i)zÔTell connected clients a session was reclaimed out from under them. Broadcast, not session-targeted: reap
paths run on timer threads with no contextvar binding and no live transport, so ``_emit`` would hit stdio.Nzsession.reclaimedr,   rþ   rH   Ústored_session_idrD   rj   z"session.reclaimed broadcast failedTr“   )Ú_RECLAIM_END_REASONSÚ_broadcast_global_eventr   ra   r7   rR   rð   )r   ru   s   &&r   Ú_announce_session_reclaimedrF  %  s…   € ð Ô-Ô-ÙðJÜÐ 3Øœ#˜gŸk™k¨&Ó1×7Ð7°RÓ8Ø¤ W§[¡[°Ó%?×%EÐ%EÀ2Ó!FØ�jð6"ö 	#øô ô JÜ�‰Ð9ÀDˆ×IðJús   �#A' ³#A' ÁA' Á'"BÂBr,   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   r   r   rj   r   r,   r/   rZ   r	   )r
   s   "r   r   r   3  s0   € ÷ Kñ K°4ð KÀð KÐUXð KÐbfñ Kr   c               ó~  € \        V P                  R4      ;'       g    R4      pV'       g   R#  ^ RIHp V! V4      pT'       g   R# T Uu. uF'  p\        TP                  R4      ;'       g    R4      NK)  	  ppT Uu. uF  qˆ'       g   K  TNK  	  pp \        R	R
\        T;'       g    T P                  R4      ;'       g    R4      RTRTR\        T4      RT/4       R#   \         d    \
        P                  RRR7        R# i ; iu upi u upi   \         d    \
        P                  RRR7        R# i ; i)u  Tell connected clients pending gateway approvals are being dropped (interrupt/reap/teardown, #106678).

Broadcast, not session-targeted: reap/interrupt run on timer threads with no live transport or contextvar,
so ``_emit`` would miss detached clients (same as ``session.reclaimed``). Fail-open by design: a missing
session key, an empty queue, and a broadcast failure never raise â€” the deny-resolve / teardown must proceed
either way (silence in the notice channel must not strand the agent thread or the session teardown).
rD   rH   N)Úlist_gateway_approvalszlist_gateway_approvals failedTr“   r¶   zapproval.cancelledr,   rþ   rC  rj   Úcancelled_countÚrequest_idsz#approval.cancelled broadcast failed)	r   ra   r6  rI  r7   rR   rð   rE  Úlen)	r   rj   r,   rD   rI  r–   ÚitemrK  Úrids	   &&$      r   Ú%_announce_cancelled_gateway_approvalsrO  3  s#  € ô �g—k‘k -Ó0×6Ð6°BÓ7€KßÙðÝ9Ù(¨Ó5ˆ÷ ÙÙAHÓIÁ¸”3�t—x‘x Ó-×3Ð3°Ö4Á€KÐIÙ"-Ó5¡+˜3³—3�3¡+€KÐ5ðKÜÐ 4Øœ#˜j×EÐE¨G¯K©K¸Ó,?×EÐEÀ2ÓFØ Ø�fØœs 7›|Ø˜;ð7(ö 	)øô ô Ü�‰Ð4¸tˆÔDÚðüò
 JùÚ5øô ô KÜ�‰Ð:ÀTˆ×JðKúsA   °C# Á!DÁ.DÁ?	DÂDÂ-D ÃD Ã#"D	ÄD	Ä"D<Ä;D<ru   c               ó$   € V ^8„  d   QhRRRRRR/# r  r	   )r
   s   "r   r   r   S  s"   € ÷ ñ ˜{ð ¸3ð ÐQUñ r   c          	     ó  € V '       g   R# \        WR7       \        W4       \        P                  ! \        4      ;_uu_ 4        \        W4       RRR4       \        P                  ! \        4      ;_uu_ 4        ^ RIHp V P                  R4      ;p'       d    V P                  R4      '       g	   V! V4       RRR4       \        P                  ! \        4      ;_uu_ 4        \        V 4      ;_uu_ 4        \        V P                  R4      ;pR4      '       d   VP                  4        RRR4       RRR4       R#   + '       g   i     Lõ; i  + '       g   i     LŸ; i  + '       g   i     L@; i  + '       g   i     R# ; i)zÜFully tear down a session: finalize, unregister notifier, close agent (``session.close`` + WS reaper). The
slash-worker is closed in ``_finalize_session`` (the single chokepoint), NOT here. Idempotent via ``_finalized``.N©ru   )Úunregister_gateway_notifyrD   r¢   r  rä   )r@  rF  r5   r6   r7   rO  r6  rS  ra   r2  r1  rä   )r   ru   rS  rd   r  s   &$   r   Ú_teardown_sessionrT  S  sô   € ÷ ÙÜ�gÕ5Ü Ô4Ü	×	Ò	œY×	'Õ	'ô 	.¨gÔB÷ 
(ô 
×	Ò	œY×	'Õ	'Ý<à—;‘;˜}Ó-Ð-ˆCÖ-°w·{±{ÐCV×7WÒ7WÙ% cÔ*÷	 
(ô 
×	Ò	œY×	'Õ	'Ô)GÈ×)PÕ)PÜ˜GŸK™K¨Ó0Ð0�5°'×:Ò:Ø�K‰KŒM÷ *Q×	'Ñ	'÷ 
(×	'ú÷ 
(×	'ú÷ *Q×)Pú×	'×	'Ð	'úsB   ÁD=Á:6EÂ1EÃ#E6Ã74E#	Ä+E6Ä=E	ÅE 	Å#E3Å.E6Å6F	c               ó$   € V ^8„  d   QhRRRRRR/# )r   rX   r   r   r   r/   rZ   r	   )r
   s   "r   r   r   j  s!   € ÷ ñ ˜ð  dð °tñ r   c                óÌ   € \         ;_uu_ 4        \        P                  V 4      VJ d   W!R&    RRR4       R#  RRR4       VP                  4        R#   + '       g   i     L"; i)zkStore worker on session iff sid still maps to it, else close it (a concurrent teardown popped the session).r,  N)r¸   r¨   ra   rä   )rX   r   r?  s   &&&r   Ú_attach_workerrW  j  sE   € ç	ŽÜ�=‰=˜Ó Ó(Ø&,�NÑ#Ø÷ 
‰Ø(÷ 
ð ‡L�L†N÷	 
�ús   �AÁA#	zdict[str, float]Ú_closed_session_activityc               ó    € V ^8„  d   QhRRRR/# )r   rX   r   r/   r   r	   )r
   s   "r   r   r   w  s   € ÷ ñ ˜Cð  Kñ r   c           	     ó  € \         ;_uu_ 4        \        P                  V R4      pVeÆ   ^ RIHp \        \        VP                  R4      ;'       g    V! 4       4      P                  4       4      pVP                  R4      '       d   \        P                  4       M#\        VP                  R4      ;'       g    ^ 4      p\        \        P                  V^ 4      V4      \        V&   RVR&   WR&   RRR4       V#   + '       g   i     X# ; i)	uØ   Atomically detach one live session from the registry â€” the ownership claim for teardown (a concurrent
close/reaper no-ops). Separate from ``_teardown_session``: slow finalization must not run under the resume lock.N)Úget_hermes_homerB   ÚrunningÚlast_activeTÚ_closingrþ   )r¸   r¨   r£   Úhermes_constantsr[  r   ÚPathra   Úresolverƒ   ÚfloatÚmaxrX  )rX   r   r[  Úhomer]  s   &    r   Ú_pop_session_by_idre  w  sÏ   € ÷ 
ŽÜ—-‘-  TÓ*ˆØÒÝ8ä”t˜GŸK™K¨Ó7×LÐL¹?Ó;LÓM×UÑUÓWÓXˆDØ)0¯©°Y×)?Ò)?œ$Ÿ)™)œ+ÄUÈ7Ï;É;ÐWdÓKe×KjÐKjÐijÓEkˆKÜ-0Ô1I×1MÑ1MÈdÐTUÓ1VÐXcÓ-dÔ$ TÑ*Ø"&ˆG�JÑØ!�F‰O÷ 
ð €N÷ 
Žð €Nús   �AC9Á4C9Â0C9Â87C9Ã9D
	c               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r   ru   r   r/   rv   r	   )r
   s   "r   r   r   ‡  s"   € ÷ ñ  kð À#ð ÐX\ñ r   c               óh  € V f   R# V P                  R4      pVR8w  dz   Vev   V\        P                  4       Jd^    VP                  4       '       d   VP	                  \
        R7       VP                  4       '       d   \        P                  R\
        4       VR8w  d   \        V 4        \        WR	7       ^ R
IHp T! V P                  R4      ;'       g    R4       R#   \         d    \        P                  RRR7        Lli ; i  ^ R
IHp T! T P                  R4      ;'       g    R4       i ; i)zDFinish a close after the caller has atomically detached the session.Fr#   Útui_shutdown)Útimeoutz:session turn thread still alive after %.1fs teardown gracez&failed waiting for session turn threadTr“   rR  )Úforget_sessionrþ   rH   )ra   Ú	threadingÚcurrent_threadÚis_aliveÚjoinÚ!_TURN_SETTLE_BEFORE_CLOSE_SECONDSrR   rS   r7   rð   Ú"_settle_isolated_turn_before_closerT  Útui_gateway.event_replayrj  )r   ru   Ú
run_threadrj  s   &$  r   Ú_teardown_popped_sessionrs  ‡  sÿ   € à‚ÙØ—‘˜]Ó+€JØ�^Ô#¨
Ò(>À:ÔU^×UmÑUmÓUoÓCoð	RØ×"Ñ"×$Ò$Ø—‘Ô(I�ÔJØ×"Ñ"×$Ò$Ü—‘ØPÔRsôuð �^Ô#Ü*¨7Ô3ð2Ü˜'Õ9õ 	<Ù�w—{‘{ 6Ó*×0Ð0¨bÔ1Ùøô ô 	RÜ�L‰LÐAÈDˆLÖQð	Rûõ 	<Ù�w—{‘{ 6Ó*×0Ð0¨bÕ1ús)   ¼C  Á+C  Á>C  Â+D Ã "DÄDÄ)D1zdict[str, Any]rÙ   c               ó    € V ^8„  d   QhRRRR/# r    r	   )r
   s   "r   r   r   ¥  s   € ÷ Rñ R°ð R¸ñ Rr   c                óˆ  € V P                  R4      '       d   \        V 4      '       g   R# \        P                  ! \        4      ;_uu_ 4        \        \        V 4      V 4       RRR4       \        P                  4       \        ,           pV P                  R4      '       d1   \        P                  4       V8  d   \        P                  R4       KG  V R,          ;_uu_ 4        V P                  R4      '       d   V P                  RR4      ;pf    RRR4       R# W R&   V\        \        VP                  4      &   \        P                  4       \        \        VP                  4      &   RRR4       \         P#                  R\        V P                  R4      4       R#   + '       g   i     ELC; i  + '       g   i     LP; i)	uù  An isolated turn runs in the compute-host child, not on ``_run_thread``: interrupt it and give it the
same close grace, and if it still has not settled keep the REAL lease out of finalize's release â€” the
completion callback releases it on the correlated turn.end/turn.error (child death fails pending turns
the same way). The RPC close is bounded; ownership ends with the child's last write, never with the
grace timer, else a second backend acquires the stored session while the child is still writing.Ú_compute_host_turn_idNrÀ   r   r\   Ú_deferred_active_session_leasez^isolated turn still live after %.1fs close grace; holding lease for %s until the child settlesrD   )ra   Ú_session_uses_compute_hostr5   r6   r7   r¹   r  rƒ   Ú	monotonicro  rÂ   r£   rÙ   r   r^   Ú#_deferred_active_session_lease_agesrR   rS   )r   Údeadlinerq   s   &  r   rp  rp  ¥  s5  € ð �;‰;Ð.×/Ò/Ô7QÐRY×7ZÒ7ZÙÜ	×	Ò	œY×	'Õ	'ÜÔ 2°7Ó ;¸WÔE÷ 
(ä�~‰~ÓÔ"CÕC€HØ
�+‰+Ð-×
.Ò
.´4·>±>Ó3CÀhÔ3NÜ�
‰
�4ÖØ	�×	 ×	 Ø�{‰{Ð2×3Ò3ÀÇÁÐMcÐeiÓAjÐ8j¸Ò7sØ÷ 
!Ñ	 ð 5:Ð0Ñ1Ø?DÔ'¬¨E¯N©NÓ(;Ñ<ÜCGÇ9Á9Ã;Ô+¬C°·±Ó,?Ñ@÷ 
!ô ‡N�NÐsÜ4°g·k±kÀ-Ó6PöR÷ 
(×	'Ð	'ú÷
 
!×	 ús   ÁFÃ"/F1ÄAF1ÆF.	Æ1G	g      œ@rz  c               ó    € V ^8„  d   QhRRRR/# )r   Únowúfloat | Noner/   r¾   r	   )r
   s   "r   r   r   È  s   € ÷ ñ  \ð ¸Sñ r   c                óö  € V f   \         P                  4       MT p \        \        P                  4       4       UUu. uF  w  rW,
          \        8”  g   K  VNK  	  ppp^ pV F�  p\        P                  VR4       \        P                  VR4      pVf   K5  \        ^VP                  4      ;pe   \        P                  RVVR7       Ki  \        P                  RV\        4       V^,          pK�  	  V# u uppi )zYForce-release deferred leases whose settlement callback never arrived. Returns the count.Nz>Failed to force-release stale deferred active session lease %sr“   zƒForce-released deferred active session lease %s held past %.0fs without a compute-host settlement (zombie concurrency slot, #62823))rƒ   r0  rz  r©   Ú*_DEFERRED_ACTIVE_SESSION_LEASE_TTL_SECONDSr£   rÙ   rÆ   r   rR   rS   )r}  r^   Údeferred_atÚstaleÚreapedrq   rÍ   s   &      r   Ú_reap_stale_deferred_leasesr„  È  sñ   € àšŒ$�)‰)Œ+¨#€Cä.2Ô3V×3\Ñ3\Ó3^Ô._ôÙ._Ñ*�XØÕÔIÑI÷ 	ˆÑ._ð 
ñ ð €FÛˆÜ+×/Ñ/°¸$Ô?Ü/×3Ñ3°H¸dÓCˆØŠ=ÙÜ  5§=¡=Ó1Ð1ˆCÒ>Ü�N‰NÐ[Ð]eØ$'ð ô )áÜ�‰ð SàÔ!Kô	Mð 	�!�Šñ ð €Mùó%s   »C5ÁC5c               ó    € V ^8„  d   QhRRRR/# r    r	   )r
   s   "r   r   r   à  s   € ÷ Wñ W°Dð W¸Tñ Wr   c                ó@  € V P                  RR4      pVf   R# \        P                  \        VP                  4      R4       \        P                  \        VP                  4      R4       \        ^VP                  4      ;pe   \        P                  RVR7       R# R# )zdSettlement half of ``_settle_isolated_turn_before_close``; a no-op for sessions that never deferred.rw  Nz.Failed to release deferred active session slotr“   )	r£   rÙ   r   r^   rz  rÆ   r   rR   rS   )r   rq   rÍ   s   &  r   Ú&_release_deferred_active_session_leaser‡  à  sz   € à�K‰KÐ8¸$Ó?€EØ‚}ÙÜ#×'Ñ'¬¨E¯N©NÓ(;¸TÔBÜ'×+Ñ+¬C°·±Ó,?ÀÔFÜ˜A˜uŸ}™}Ó-Ð-ˆÒ:Ü�‰ÐGÐRUˆÖVñ ;r   Ú	predicatec               ó(   € V ^8„  d   QhRRRRRRRR/# )r   rX   r   ru   rˆ  zCallable[[dict], bool] | Noner/   rv   r	   )r
   s   "r   r   r   ë  s2   € ÷ Dñ DØ	ðDØ ðDØ;XðDØdhñDr   c               óò   € \         ;_uu_ 4        \        P                  V 4      pVe   Ve   V! V4      '       g    RRR4       R# \        V 4      pRRR4       \	        XVR7      #   + '       g   i     L; i)aM  Idempotent teardown funnel for callers with no resume race (resume-sensitive callers pop under
``_session_resume_lock`` and call ``_teardown_popped_session`` after releasing it). Automatic reapers pass
``predicate`` to revalidate under ``_sessions_lock`` right before the claim, so a stale scan can't close a
session that reattached.NFrR  )r¸   r¨   ra   re  rs  )rX   ru   rˆ  Úcurrentr   s   &$$  r   Ú_close_session_by_idrŒ  ë  s]   € ÷ 
ŽÜ—-‘- Ó$ˆØÒ  g¢o¹YÀw×=OÒ=OØ÷ 
‰ô % SÓ)ˆ÷	 
ô
 $ G¸
ÔCÐC÷ 
�ús   �+A&»A&ÁA&Á&A6	c               ó    € V ^8„  d   QhRRRR/# rÈ   r	   )r
   s   "r   r   r   ù  s   € ÷ rñ r [ð r°Tñ rr   c                ó’   € \        T ;'       d6    V P                  R4      '       * ;'       d    V P                  R4      \        J 4      # )zFTrue if a live session is still bound to the disconnected-WS sentinel.r¦   r§   )rv   ra   Ú_detached_ws_transport©r   s   &r   Ú_ws_session_is_detachedr‘  ù  s8   € ä�×pÐp §¡¨LÓ 9Ô9×pÐp¸g¿k¹kÈ+Ó>VÔZpÐ>pÓqÐqr   c               ó    € V ^8„  d   QhRRRR/# rÈ   r	   )r
   s   "r   r   r   þ  s   € ÷ Qñ Q [ð Q°Tñ Qr   c                óf   € \        \        V 4      ;'       d    V P                  R4      '       * 4      # )zoTrue if a WS session sits on ``_detached_ws_transport`` (where ``handle_ws`` parks disconnected clients), idle.r\  )rv   r‘  ra   r�  s   &r   Ú_ws_session_is_orphanedr”  þ  s'   € äÔ'¨Ó0×OÐO¸¿¹ÀYÓ9OÔ5OÓPÐPr   r¶   ÚorphanFc          
     ó,   € V ^8„  d   QhRRRRRRRRR	R/# )
r   rX   r   r   r   r¶   r-   r•  rv   r/   r	   )r
   s   "r   r   r     s;   € ÷ Rñ RØ	ðRØðRØ,6ðRØGKðRà	ñRr   c               ó^  € \        V4      p\        VP                  R4      4      p\        VP                  R4      4      ;'       d    V'       * pRpV'       d;   V'       g   VP                  R4      '       d   \        4       P	                  WR7       M-VP                  R4      ;pRJ;'       d    VP                  4       pVR,          ;_uu_ 4        R	VR
&   RVR&   VP                  RR4       \        VP                  R^ 4      4      ^,           VR&   RRR4       V'       dC    ^ RIH	p	 \        VRR7      ;_uu_ 4        V	! RVP                  RR4      RRRR7       RRR4       V'       gé   V'       d   ^ RIHp
 V
! VP                  R4      4       \         P"                  ! \        4      ;_uu_ 4        ^ RIHp T! \)        W4      R\+        \-        VP                  R4      RR4      ;'       g    R4      R7       RRR4       V'       gJ   V'       gB   VR,          ;_uu_ 4        VP                  R4      '       d   RVR&   \/        V4       RRR4       VP                  R4      ;pe=   \         P"                  ! \        4      ;_uu_ 4        ^ RIHp V! VRRR 7       RRR4       \5        V 4       \         P"                  ! \        4      ;_uu_ 4        V'       d   R!MR"p\7        WV R#7       ^ R$IHp V! VR,          R%R	R&7       RRR4       V#   + '       g   i     EL; i  + '       g   i     ELÏ; i  \         d    \        P                  RR	R7        EL÷i ; i  + '       g   i     ELm; i  + '       g   i     EL0; i  + '       g   i     Lò; i  + '       g   i     T# ; i)'u°  Apply the shared ``session.interrupt`` contract to one claimed session; returns whether the compute-host control
channel was used. The WS orphan reaper reuses this so a dead client gets the same partial-history/queue semantics.

``orphan=True`` (reaper path) labels dropped approvals ``ws_orphan_reap``; the label comes from the
caller, never from request_id prefix sniffing â€” a future orphan caller may use another id (#106678).
Ú_manual_compress_activer\  FÚ_compute_host_activerµ   r#   Nr   TÚ_turn_cancel_requestedÚqueued_promptÚqueued_promptsÚ_queued_prompt_generationr  )Úhydrate_secretsÚagent_loop_stoppedrD   rH   rA   Ú	user_stopÚsession_interrupt)rD   r.   rj   Úinvalidation_reasonz'agent_loop_stopped hook dispatch failedr“   )Úrequest_hard_interruptr  r"  r,   )r$  rj   Úparent_session_idr&  zsession interruptedr)  Úws_orphan_reapÚ	interrupt)r,   )Úresolve_gateway_approvalÚdeny)Úresolve_all)rx  rv   ra   Ú_get_compute_host_supervisorr¦  rm  r£   r¾   Úhermes_cli.pluginsr2   r2  r7   rR   rð   Úagent.interrupt_compatr£  r5   r6   r5  r#  r  r   rn   Ú_clear_inflight_turnr7  r'  Ú_clear_pendingrO  r6  r§  )rX   r   r¶   r•  Úuse_compute_hostÚcompressingÚshould_interruptÚrun_thread_aliveÚrtÚ_invoke_hookr£  r#  Úagent_for_reviewr'  rj   r§  s   &&$$            r   r¹   r¹     sß  € ô 2°'Ó:Ðô �w—{‘{Ð#<Ó=Ó>€KÜ˜GŸK™K¨	Ó2Ó3×GÐG¸K¼ÐØÐß÷ ˜wŸ{™{Ð+A×BÒBÜ(Ó*×4Ñ4°SÐ4ÔPøà")§+¡+¨mÓ"<Ð<˜BÀTÐI×[Ð[ÈbÏkÉkËmÐØ	�×	 ×	 Ø,0ˆÐ(Ñ)Ø#'ˆ�Ñ Ø�‰Ð$ dÔ+Ü/2°7·;±;Ð?ZÐ\]Ó3^Ó/_ÐbcÕ/cˆÐ+Ñ,÷	 
!÷
 ð	SÝFÜ/°È×OÖOÙØ(°g·k±kÀ-ÐQSÓ6TÐ_dØ&Ð<Oõ÷ P÷ ßÝEÙ" 7§;¡;¨wÓ#7Ô8ô × Ò ¤×+Õ+ÝDÙ!Ü%7¸Ó%EÈkÜ"%¤g¨g¯k©k¸'Ó.BÀLÐRTÓ&U×&[Ð&[ÐY[Ó"\õ^÷ ,÷
  ¯Ø˜×(×(Ø—;‘;˜y×)Ò)Ø).�G˜IÑ&Ü(¨Ô1÷ )ð $ŸK™K¨Ó0Ð0ÐÒ=Ü× Ò ¤×+Õ+ÝVÙ2Ø Ð*?ÐMbõd÷ ,ô �3ÔÜ	×	Ò	œY×	'Õ	'÷
 &,Ñ!°ˆÜ-¨gÈ#ÕNÝ;Ù  ¨Õ!7¸ÈTÕR÷ 
(ð Ð÷y 
!×	 Ð	 ú÷ P×OÐOûô
 ô 	SÜ�L‰LÐBÈTˆL×Rð	Sú÷ ,×+Ð+ú÷ )×(Ð(ú÷ ,×+ú÷
 
(Ö	'ð Ðúsn   ÃALÄ$L7 Ä?L#ÅL7 Æ4AM È%(M4ÊNË2NÌL 	Ì#L4	Ì.L7 Ì4L7 Ì7"MÍMÍ M1	Í4N	ÎN	ÎN,	c               ó$   € V ^8„  d   QhRRRRRR/# )r   rX   r   r   r   r/   rv   r	   )r
   s   "r   r   r   X  s!   € ÷ ñ ¨ð °{ð Èdñ r   c           
     óL  € Vf-   \         ;_uu_ 4        \        P                  V 4      pRRR4       V'       g   R# \        W4      p\	        VP                  R4      ;'       g    R4      ;r4\        VP                  R4      RR4      ;'       g    TpV'       dˆ   \        P                  ! \        4      ;_uu_ 4        \        V4      ;_uu_ 4       pVe=   \        VP                  V4      ;'       g    / P                  RR4      4      '       d   RpRRR4       RRR4       V'       g   V'       g   R#  ^ RIHp V! W2R	7      #   + '       g   i     EL"; i  + '       g   i     LN; i  + '       g   i     LY; i  \         d    \        P                  R
T RR7        R# i ; i)uî   True when UI session ``sid`` still owns live background work â€” by live UI sid AND, when the TUI owns the durable
lifecycle (never for gateway-viewer tabs), by session_key so a delegation from an earlier tab keeps it alive.

See #60609.
NFrD   rH   r  r,   r_   )Úhas_live_for_session)rD   r$  z4Failed to query active delegations for UI session %sTr“   )r¸   r¨   ra   r  r   rn   r5   r6   r7   r˜   rú   r3  r5  r¸  rR   rð   )rX   r   r  Úowned_session_keyrD   r,   r‡   r¸  s   &&      r   Ú_session_has_active_delegationsrº  X  s2  € ð ‚ßŽ^Ü—m‘m CÓ(ˆG÷ çÙÜ  Ó.€GÜ&)¨'¯+©+°mÓ*D×*JÐ*JÈÓ&KÐKÐÜ˜Ÿ™ WÓ-¨|¸TÓB×QÐQÀk€Jßô
 × Ò ¤×+Õ+¬[¸×-AÔ-AÀRØŠ~Ô":¸B¿N¹NÈ:Ó<V×<\Ð<\ÐZ\×;aÑ;aÐbjÐlnÓ;o×"pÒ"pØ$&Ð!÷ .B×+÷ ×,ÙðÝ?Ù#Ð0AÔ`Ð`÷' �^ˆ^ú÷ .B×-Aú×+×+ûô ô Ü�‰ÐKÈSÐ[_ˆÔ`ÚðúsM   “EÂ;E)Ã!E	Ã1E	ÄE	ÄE)Ä3E< ÅE	ÅE&Å!E)Å)E9	Å<#F#Æ"F#zdict[str, threading.Timer]Ú_pending_ws_reapsc               ó    € V ^8„  d   QhRRRR/# )r   rX   r   r/   rZ   r	   )r
   s   "r   r   r   }  s   € ÷ ñ  ð ¨ñ r   c                ó0  € \         ;_uu_ 4        \        P                  V R4      pRRR4       Xe>   \        P                  ! \
        4      ;_uu_ 4        VP                  4        RRR4       R# R#   + '       g   i     LS; i  + '       g   i     R# ; i)zÔCancel a pending WS-orphan reap for ``sid`` (client came back). Called from every path that re-binds a live
transport; closes the fired-but-not-run Timer race and stops dead Timers accumulating on flappy clients.N)r¸   r»  r£   r5   r6   r7   Úcancel)rX   Útimers   & r   Ú_cancel_ws_orphan_reaprÀ  }  sa   € ÷ 
ŽÜ!×%Ñ% c¨4Ó0ˆ÷ 
àÒÜ× Ò ¤×+Õ+Ø�L‰LŒN÷ ,Ñ+ñ ÷ 
�ú÷ ,×+Ð+ús   �A1ÁBÁ1B	ÂB	c               ó$   € V ^8„  d   QhRRRRRR/# )r   rX   r   r   r   r/   r   r	   )r
   s   "r   r   r   ‡  s!   € ÷ ñ  ð ¨dð °{ñ r   c                óš   € \         P                  V4      VJd   \        V RR4      # VP                  R4      '       d   \        V RR4      # R# )uù   Under ``_session_resume_lock``: why a reattaching RPC (resume/activate/prompt.submit) must NOT rebind
``session`` â€” it is stale, or a client-gone interrupt is still settling and the reap Timer must keep
polling. None when the reattach may proceed.i§  z$session no longer live; retry resumeÚ _client_gone_interrupt_requestedi©  z%session disconnect interrupt settlingN)r¨   ra   Ú_err)rN  rX   r   s   &&&r   Ú_reattach_refusalrÅ  ‡  sH   € ô ‡}�}�SÓ Ó(Ü�C˜ÐEÓFÐFØ‡{�{Ð5×6Ò6Ü�C˜ÐFÓGÐGÙr   c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   rX   r   r   r   r§   Ú	Transportr/   rZ   r	   )r
   s   "r   r   r   ’  s(   € ÷ $ñ $ ð $¨dð $¸yð $ÈTñ $r   c                óv  € V\         JdR   \        V4      '       dA   \        ;_uu_ 4        \        V4      '       d   V \        9  d   \        V 4       RRR4       R# \        W4       \        P                  4       VP                  R/ 4      V&   V\         Jd   \        V 4       R# R#   + '       g   i     R# ; i)a
  Attach a live peer without displacing existing subscribers (caller holds ``history_lock``).
Subagent control authority needs no bookkeeping here: it resolves against ``session["transport"]``
at RPC time (``tools.delegate_tool_registry._subagent_transport_matches``).NÚviewers)
r�  r¬   r¸   r‘  r»  Ú_schedule_ws_orphan_reapÚ_attach_session_transportrƒ   Ú
setdefaultrÀ  )rX   r   r§   s   &&&r   Ú_rebind_live_transportrÍ  ’  sŽ   € ð Ô.Ó.Ô3EÀi×3PÒ3P÷ Ž^Ü& w×/Ò/°CÔ?PÔ4PÜ(¨Ô-÷ ñ 	Ü˜gÔ1ô 48·9±9³;€G×Ñ�y "Ó% iÑ0àÔ.Ó.Ü˜sÖ#ñ /÷ Ž^ñ 	ús   ª(B'Â'B8	c               ó    € V ^8„  d   QhRRRR/# )r   r   r   r/   rv   r	   )r
   s   "r   r   r   §  s   € ÷ ñ ¨tð ¸ñ r   c                óŽ  € \         ^ 8:  d   R# V P                  R4      '       dš   V R,          ;_uu_ 4        V P                  R4      pV P                  RR4      ;'       dS    \        V\        4      ;'       d;    ^ \        P                  4       V,
          R,          u;8*  ;'       d
    \         8  Mu uuRRR4       # \        \        V P                  R4      R	R4      ;p4      '       g   R#  V! 4       P                  R
4      pVRJ;'       d    \        V4      \         8  #   + '       g   i     Lt; i  \         d     R# i ; i)uÕ  Whether a detached RUNNING turn's activity clock (``_touch_activity``) is still fresh â€” the reaper must NOT
interrupt healthy detached work (closed laptop). Conservative: disabled threshold, missing/opaque agent, unreadable
summary or never-stamped clock all report NOT fresh (eligible for interrupt-at-grace) to keep the wedged-turn net.

Reuses the agent's existing activity summary (``_touch_activity`` is stamped by API waits, stream
tokens, and tool heartbeats â€” the same clock the turn-liveness watchdog samples; see
agent/turn_liveness.py). See #100325, #98028.
Isolated turns mirror that clock from the child under a unique dispatch token;
their monotonic samples keep aging even if the child or its pipe stalls.
Frv  r   Ú_compute_host_activity_nsr\  i Êš;Nr  Úget_activity_summaryÚseconds_since_activity)
Ú_WS_ORPHAN_ACTIVITY_STALE_Sra   rb   r¾   rƒ   Úperf_counter_nsÚcallablern   rb  r7   )r   ÚstampÚ
summary_fnÚelapseds   &   r   Ú!_ws_orphan_turn_activity_is_freshrÙ  §  s  € ô # aÔ'ÙØ‡{�{Ð*×+Ò+Ø�^×$×$Ø—K‘KÐ ;Ó<ˆEØ—K‘K 	¨5Ó1÷ lð l´jÀÌÓ6L÷ lð lØœd×2Ñ2Ó4°uÕ<ÀÕM×kÔkÔPkÔk÷ %Ò$ô ¤'¨'¯+©+°gÓ*>Ð@VÐX\Ó"]Ð]�J×^Ò^ÙðÙ“,×"Ñ"Ð#;Ó<ˆØ˜dÐ"×SÐS¤u¨W£~Ô8SÑ'SÐS÷ %×$ûô ô Úðús0   ¶AD"Á9.D"Â(D"Ã. D5 ÄD5 Ä"D2	Ä5EÅEÚdelay_sÚ_expected_timerc               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   rX   r   rÚ  r~  rÛ  zthreading.Timer | Noner/   rZ   r	   )r
   s   "r   r   r   Â  s2   € ÷ yñ yØ	ðyØ&ðyØ@Vðyà	ñyr   c               óÈ  a aaaa€ \         ^ 8:  d   R# Vf   \         M\        RV4      o\        P                  4       o\        P                  4       oR VVVV V3R llp\        ;_uu_ 4        Ve%   \
        P                  S 4      VJd    RRR4       R# \        P                  Vf   \         M\        RV4      V4      oRSn	        \
        P                  S R4      pS\
        S &   RRR4       Xe<   \        P                  ! \        4      ;_uu_ 4        VP                  4        RRR4       SP                  4        R#   + '       g   i     La; i  + '       g   i     L5; i)uç  After a grace window, reap session ``sid`` iff it's still orphaned. Called from the WS-disconnect path; a
reconnect or ``session.resume`` cancels the reap by re-binding a live transport. Disabled when grace is 0.

The grace is measured in AWAKE (monotonic) time: ``threading.Timer``'s wait elapses in wall-clock time on
platforms without a monotonic condvar (macOS lacks ``pthread_condattr_setclock``), so a system sleep makes
the timer fire "early" in awake-time terms. Without the sleep check below, closing a laptop lid for longer
than the grace reaped the parked session at the instant of wake â€” before the Desktop's WS reconnect or
``session.resume`` could re-bind a transport â€” so every sleep/wake cycle 404'd the open chat (#44183).Nç        c               ó   € V ^8„  d   QhRR/# rà   r	   )r
   s   "r   r   Ú._schedule_ws_orphan_reap.<locals>.__annotate__Ö  s   € ÷ YGñ YG�4ñ YGr   c                 ó®  <€ \         P                  4       S	,
          \         P                  4       S,
          ,
          p V \        8”  dE   \        R S
\         P                  4       S,
          ,
          4      pV^ 8:  d   M\	        SVSR7       R# R;p;r4\
        ;_uu_ 4        \        ;_uu_ 4        \        P                  S4      SJd    RRR4       RRR4       R# \        P                  S4      pVf*   \        P                  SR4        RRR4       RRR4       R# \        V4      '       gN   VP                  RR4       VP                  RR4       \        P                  SR4        RRR4       RRR4       R# \        SV4      '       gQ   VP                  R4      '       gB   VP                  R4      '       g+   \        V4      '       g   \        V4      '       d	   \        pEMVP                  R4      '       g   \!        S4      pMåVP                  R4      '       g4   \#        V4      '       d#   \$        P'                  RS\(        4       \        pM›\+        VP                  R4      ;'       g    ^ 4      ^,           ;qeR&   V\,        8”  d>   \$        P/                  RSV^,
          V^,
          \0        ,          4       \!        S4      pM$VP                  R4      '       g   RVR&   Tp\0        pVf   \        P                  SR4       RRR4       RRR4       Ve+    \3        SVR	S 2RR
7      p\$        P5                  RSV4       Ve   \	        SVSR7       R# Ve.   VP                  R4      '       d   \$        P5                  RS4       \;        VRR7       R#   + '       g   i     Lš; i  + '       g   i     L¥; i  \6         d‹    \$        P9                  RS4       \        ;_uu_ 4        \        P                  S4      TJ d,   \        P                  S4      SJ d   TP                  RR4       RRR4        Kù    + '       g   i      EL; ii ; i)rÞ  )rÚ  rÛ  NrÃ  Ú_client_gone_interrupt_pollsr\  zLclient_gone sid=%s action=defer (turn activity fresh; stale threshold %.0fs)uk   client_gone sid=%s: turn did not settle after %d interrupt polls (%.0fs) â€” force-reaping detached sessionTzclient-gone-)r¶   r•  z5client_gone sid=%s action=interrupt turn_isolation=%sz#client_gone interrupt failed sid=%szclient_gone sid=%s action=reapr¥  rR  )rƒ   ry  Ú_WS_ORPHAN_REAP_SLEEP_SLACK_Src  rÊ  r·   r¸   r»  ra   r¨   r£   r‘  rº  Ú"_session_owns_live_wakeup_scheduleÚ*_session_owns_pending_process_notificationÚ_WS_ORPHAN_REAP_GRACE_Sre  rÙ  rR   rð   rÓ  r¾   Ú#_WS_ORPHAN_INTERRUPT_REAP_MAX_POLLSÚerrorÚ _WS_ORPHAN_INTERRUPT_REAP_POLL_Sr¹   r‹   r7   rº   rs  )Úslept_sÚrearm_delayÚreschedule_delayÚinterrupt_sessionr   r‹  ÚpollsÚisolatedÚarmed_monotonicÚ
armed_wallÚgrace_srX   r¿  s           €€€€€r   Ú_reapÚ'_schedule_ws_orphan_reap.<locals>._reapÖ  sw  ø€ ô —9‘9“; Õ+´·±Ó0@À?Õ0RÕSˆØÔ2Ô2Ü˜c 7¬d¯n©nÓ.>ÀÕ.PÕ#QÓRˆKØ˜aÔØô
 )¨°kÐSXÕYÙð :>Ð=ÐÐ=Ð,ß!Ö!§>¦>ô !×$Ñ$ SÓ)°Ó6Ø÷	 $2×!Ñ!ô
  —m‘m CÓ(ˆGØŠÜ!×%Ñ% c¨4Ô0Ø÷ $2×!Ñ!ô +¨7×3Ò3ð
 —‘Ð>ÀÔEØ—‘Ð:¸DÔAÜ!×%Ñ% c¨4Ô0Ø÷# $2×!Ñ!ô$ /¨s°G×<Ò<ØŸ™ I×.Ò.Ø#ŸK™KÐ(J×KÒKÜ;¸G×DÒDÜFÀw×OÒOô $;Ò Ø—[‘[ ×+Ò+Ü,¨SÓ1‘Ø—[‘[Ð!C×DÒDÔIjÐkr×IsÒIsä—‘ÐkØ Ô"=ô?ä#:Ñ ô CFÀgÇkÁkÐRpÓFq×FvÐFvÐuvÓBwÐz{ÕB{Ð{�Ð >Ñ?àÔ>Ô>ä—L‘Lð FØ˜U Q�Y¨°­Ô6VÕ(VôXô 1°Ó5‘Gà"Ÿ;™;Ð'I×JÒJØFJ˜Ð BÑCØ,3Ð)Ü'GÐ$ØÒ'Ü!×%Ñ% c¨4Ô0÷g $2×!ðh Ò(ð	XÜ2ØÐ*¸ÀcÀUÐ7KÐTXôZ�ä—‘ÐSÐUXÐZbÔcð Ò'Ü$ SÐ2BÐTYÕZÙØÒ 7§;¡;Ð/Q×#RÒ#RÜ�K‰KÐ8¸#Ô>Ü  Ð5E×F÷I $2§>ú×!×!ûôr ô XÜ× Ñ Ð!FÈÔLß#–^Ü!Ÿ™ cÓ*Ð.?Ó?Ü 1× 5Ñ 5°cÓ :¸eÓ CØ)×-Ñ-Ð.PÐRVÔW÷ $—^—^”^úðXús›   ÂN,Â.N	Ã	N,Ã0N	ÄN,ÄAN	Å)N,Å;(N	Æ$N	Æ;A N	Ç<"N	ÈAN	É/A0N	Ë 'N	ÌN,Ì)N? ÎN)Î$N,Î,N<	Î?/QÏ.AP>Ð3QÐ>QÑ	QÑQT)ræ  rc  rƒ   ry  r¸   r»  ra   rk  ÚTimerÚdaemonr£   r5   r6   r7   r¾  r&   )	rX   rÚ  rÛ  ró  Úpriorrð  rñ  rò  r¿  s	   f$$  @@@@r   rÊ  rÊ  Â  s  ü€ ô  !Ô#ÙØ)0ªÕ%¼cÀ#ÀwÓ>O€Gô —n‘nÓ&€OÜ—‘“€J÷YGô YG÷v 
ŽØÒ&Ô+<×+@Ñ+@ÀÓ+EÈ_Ó+\Ø÷ 
‰ô —‘¸7º?Õ 7ÔPSÐTWÐY`ÓPaÐchÓiˆØˆŒÜ!×%Ñ% c¨4Ó0ˆØ!&Ô˜#Ñ÷ 
ð ÒÜ× Ò ¤×+Õ+Ø�L‰LŒN÷ ,à	‡K�K†M÷ 
�ú÷ ,×+ús   Á,D>ÂAD>ÄEÄ>E	ÅE!	c               ó    € V ^8„  d   QhRRRR/# )r   ru   r   r/   ztuple[int, int]r	   )r
   s   "r   r   r   >  s   € ÷ 9ñ 9¸Cð 9ÐVeñ 9r   c               ó  € \        V 4      p^ ;r4V EF  w  rVRpRp\        ;_uu_ 4        \        ;_uu_ 4        \        P	                  V4      p	W–Jd    RRR4       RRR4       KU  V	P	                  R4      ;'       g    / P                  V R4       \        ;_uu_ 4        \        W�R7      '       d    RRR4       RRR4       RRR4       K¼   RRR4       V	P	                  R4      '       d   \        V4      pMðV	P	                  R4      ;'       g    / p
V
P                  V R4       \        V
P                  4       R R7       UUu. uF  w  r¼\        V4      '       d   K  VNK  	  pppV'       d   \        WYVR,          4       Me\        V	R&   V	P                  R	R4       V	P                  R
R4       Rp\        P                  ! \         4      ;_uu_ 4        \#        V4       RRR4       RRR4       RRR4       Ve   V\%        WqR7      ,          pEK  V'       g   EK  V^,          pEK  	  W43#   + '       g   i     ELj; iu uppi   + '       g   i     Lp; i  + '       g   i     L{; i  + '       g   i     L†; i)u°  Single WS-disconnect teardown entry point: reap close_on_disconnect sessions (sidecar/dashboard) immediately;
re-point the rest at the detached transport (later emits miss the dead socket) for the grace-windowed WS-orphan
reaper. Returns ``(reaped, detached)`` counts.

Multi-client fan-out: the departing transport is DETACHED from every session first. A session that still has
another client attached keeps streaming and is neither parked nor reaped â€” a watcher leaving must not end the
turn the remaining client is reading. Only the sessions left clientless take the historical
close_on_disconnect / park-sentinel path, so a single-client disconnect behaves exactly as it always has.NFrÉ  )Ú	excludingÚclose_on_disconnectc                ó   € V ^,          # )é   r	   )Úkvs   &r   rË   Ú/_close_sessions_for_transport.<locals>.<lambda>g  s   € ÐPRÐSTÖPUr   )rd   r§   rÃ  râ  TrR  éÿÿÿÿ)Ú_detach_transport_from_sessionsr·   r¸   r¨   ra   r£   Ú_session_transport_lockÚ_session_has_live_transportre  Úsortedr©   r¬   rÍ  r�  r5   r6   r7   rÊ  rs  )r§   ru   Ú
clientlessrƒ  ÚdetachedrX   r   Úclaimed_for_teardownÚshould_schedule_reapr‹  rÉ  ÚvtÚtsÚlives   &$            r   Ú_close_sessions_for_transportr  >  sì  € ô 1°Ó;€JØÐ€FÜ"‰ˆØ#ÐØ$Ð÷ "Ö!§>¦>Ü—m‘m CÓ(ˆGØÓ%Ø÷ $2×!Ñ!ð
 �[‰[˜Ó#×)Ð) r×.Ñ.¨y¸$Ô?÷ )Ö(Ü.¨w×LÓLØ÷ )÷ $2×!Ñ!ð M÷ )ð �{‰{Ð0×1Ò1Ü'9¸#Ó'>Ñ$ð
 "Ÿ+™+ iÓ0×6Ð6°B�à—‘˜I tÔ,Ü)/°·±³ÑEUÕ)VÔuÑ)V™v˜rÔ^pÐqs×^tŸ˜Ñ)V�ÑußÜ*¨3¸¸b½ÕBä+A�G˜KÑ(Ø—K‘KÐ BÀDÔIØ—K‘KÐ >ÀÔEØ+/Ð(ô $×,Ò,¬Y×7Õ7Ü0°Ô5÷ 8÷G $2×!ðJ  Ò+ØÔ.Ð/CÔ[Õ[‹Fß!Ò!Ø˜�M‹Hñ[ #ð\ ÐÐ÷9 )×(Ð(üó v÷ 8×7ú÷G $2§>ú×!×!ús�   ©I/¸IÁI/Á&IÁ>!IÂH/Â3IÂ;I/ÃIÃ-#IÄ4IÅIÅIÅ%A0IÇI	Ç!IÇ)I/È/I È:IÉ	IÉIÉI,É'I/É/I?c               ó   € V ^8„  d   QhRR/# rà   r	   )r
   s   "r   r   r   z  s   € ÷ 0ñ 0˜ñ 0r   c                ó2   € \        \        4       V RR7       R# )zFPublish this module's helpers onto ``server``, rebound to its globals.)ÚskipN)Ú_)r   Úglobals)Úservers   &r   Úregisterr  z  s   € ä”“	˜6¨×/r   r   >   Ú	lru_evictÚidle_timeoutrh  r;   r¥  >   rH   ÚacpÚclirA   ÚcronÚtestÚlocalÚwebuiÚkanbanrI   ÚwebhookÚsubagentÚ
api_serverÚmsgraph_webhook)rH   )r  >   r  r  r¥  )@Ú__conditional_annotations__Ú__doc__Ú
__future__r   r  r5   Ú
method_ctxr   Úcontextmanagerr   r)   r:   rT   Ú	frozensetr.  r?   rV   re   rs   r�   r�   rk   rm   r¯   ro   rÆ   rÎ   rÓ   rÚ   rì   ró   r÷   rú   r  r  r@  rD  rF  rO  rT  rW  rX  Ú__annotations__re  rs  rÙ   rp  r€  rz  r„  r‡  rŒ  r‘  r”  r¹   rº  r»  rÀ  rÅ  rÍ  rÙ  rÊ  r  r  )r!  s   @r   Ú<module>r(     s   øðôõ
 #ã ã å #ð ×Ñôó ððÀT÷ ÷2ð "\Ð Ù!*Ò+{Ó!|Ð õ0ð6Ø>Cð6Øgk÷6õ&FõBð*hÐ õõD"õJ+õ

õõ>õõ.ð 9 4÷ 9ð ×Ñô!6ó ð!6õHñD !ò "@ó AÐ õ
÷õe÷oñh !Ò!PÓQÐ õJðKÐ[]÷ Kð@À÷ õ.ð .0Ð Ð*Ó /õð È÷ ð6 35Ð  Ó 4õRð> .4Ð *Ø8:Ð #Ð%5Ó :÷õ0WðDØ#.ðDØ[_÷Dõrõ
Qð
RØ9=ðRØNS÷R÷jðD 13Ð Ð-Ó 2õõõ$õ*ð6yØ)-ðyØY]÷yðx9À/÷ 9÷x0r   