+
    iHàjDa  ã                   ó  € R 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Ht ^ RIHt ]P                   ! R4      tRtRtR	tR
tRt ! R R4      t] ! R R4      4       tR R ltR R ltR R ltR R ltR R ltR# )ue  Durable cross-process session turn lease for ``TurnFacadeMixin.run_conversation``.

One process at a time may load -> run -> flush a session shared through state.db (Desktop, CLI
resume, gateway, background delivery). ``admit_durable_turn_lease`` acquires the row lease (or
returns the early result the faÃ§ade must hand back); ``DurableTurnLease`` owns the periodic
refresher, the turn-liveness watchdog wiring, and the lease-loss / stall interrupt plumbing. Both
timers run via the shared scheduler (``agent/periodic_scheduler.py``; timer thread orders,
bodies run on per-handle workers), not per-turn threads.
N)Únullcontext)Ú	dataclass)ÚAnyÚDictÚListÚOptional)Úholder_namespace_tokenÚ	run_agentzsession turn lease lostg     Àr@g      œ@g      4@g       @c                   ó  a € ] tR t^"t o RtRR/V 3R lR lltV 3R lR ltV 3R lR	 ltV 3R
 lR ltV 3R lR lt	]	t
RV 3R lR lltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltR tRtV tR# )ÚDurableTurnLeasea6  An admitted session turn lease plus the periodic timers that keep it alive and watch the turn.

``stop`` is shared by the refresher and the liveness watchdog; ``turn_active`` gates every
interrupt so a late refresher miss can never hard-interrupt the NEXT turn. Both are read and
written only under ``_lock``.
Ú
expires_atNc                ó@   <€ V ^8„  d   QhRS[ RS[ RS[S[,          RR/# )é   Ú
session_idÚholderr   ÚreturnN)Ústrr   Úfloat)ÚformatÚ__classdict__s   "€Ú</home/ubuntu/.hermes/hermes-agent/agent/turn_facade_lease.pyÚ__annotate__ÚDurableTurnLease.__annotate__*   s/   ø€ ÷ &ñ &©cð &¹3ð &ÉxÑX]Íð &Ðjnñ &ó    c               ób  € Wn         W n        W0n        W@n        Vf!   \        P                  ! 4       \
        ,           MTV n        \        P                  ! 4       V n	        \        \        VRR4      4      V n        \        P                  ! 4       V n        RV n        R V n        R V n        . V n        R # )NÚ$_session_turn_lease_refresh_intervalg      N@F)ÚagentÚdbr   r   ÚtimeÚLEASE_TTL_SECONDSÚ_authority_deadlineÚ	threadingÚEventÚstopr   ÚgetattrÚrefresh_intervalÚLockÚ_lockÚturn_activeÚinterrupt_messageÚwatchdogÚtimer_handles)Úselfr   r   r   r   r   s   &&&&&$r   Ú__init__ÚDurableTurnLease.__init__*   s‰   € ØŒ
ØŒØ$ŒØŒð GQÒFX¤4§9¢9£;Ô1BÖ#BÐ^hˆÔ Ü—O’OÓ%ˆŒ	Ü %¤g¨eÐ5[Ð]aÓ&bÓ cˆÔÜ—^’^Ó%ˆŒ
Ø ˆÔØ04ˆÔØˆŒØ#%ˆÖr   c                ó    <€ V ^8„  d   QhRS[ /# ©r   r   ©r   )r   r   s   "€r   r   r   ;   s   ø€ ÷ Jñ J¡Sñ Jr   c                óX   € \        V P                  R R4      ;'       g    V P                  # )r   N)r$   r   r   ©r,   s   &r   Ú_current_session_idÚ$DurableTurnLease._current_session_id;   s!   € Ü�t—z‘z <°Ó6×IÐI¸$¿/¹/ÐIr   c                ó   <€ V ^8„  d   QhRR/# ©r   r   N© )r   r   s   "€r   r   r   >   s   ø€ ÷ ñ ˜tñ r   c                ó†  €  ^ RI Hp V! 4       ;'       g    / p^ RIHp VP                  V4      w  rEVey   VP                  V P                  V P                  4       VWPP                  V P                  P                  4       V P                  V P                  V P                  R7	      V n        R# R#   \         d    / p L¦i ; i)z”Create (not schedule) the liveness watchdog when configured: lease renewal is NOT
evidence of progress; a silently stalled turn would renew forever.)Úload_config_readonly)Úturn_livenessN)r   Ú	timeout_sÚpoll_sÚ
stop_eventÚactivity_lockÚis_turn_activeÚcommit_abortÚdeactivate_turn)Úhermes_cli.configr:   Ú	Exceptionr   r;   Úresolve_turn_liveness_settingsÚTurnLivenessWatchdogr4   r#   Ú_liveness_activity_lockr@   Úcommit_liveness_abortÚstop_refresherr*   )r,   r:   Úliveness_configr;   r<   r=   s   &     r   Úbuild_threadsÚDurableTurnLease.build_threads>   s¯   € ð	!Ý>á2Ó4×:Ð:¸ˆOõ 	(à)×HÑHÈÓYÑˆ	ØÒ Ø)×>Ñ>Ø—
‘
 t×'?Ñ'?Ó'AÈYØ¯)©)Ø"Ÿj™j×@Ñ@ÓBØ#×2Ñ2À×A[ÑA[Ø $× 3Ñ 3ð ?ó ˆDŽMñ !øô ô 	!Ø ŠOð	!ús   ‚B0 –B0 Â0C Â?C c                ó   <€ V ^8„  d   QhRR/# r7   r8   )r   r   s   "€r   r   r   S   s   ø€ ÷ @ñ @�tñ @r   c                óØ  € V P                   ;_uu_ 4        R V n        RRR4       T P                  P                  R4       ^ RIHp V! V P                  4       ^ RIHp V P                  P                  V! V P                  V P                  4      4       V P                  e6   V P                  P                  V P                  P                  4       4       R# R#   + '       g   i     LÄ; i)TNzstarting new turn)Úarm_turn)Úschedule)r'   r(   r   Ú_touch_activityÚ/hermes_cli.observability.shared_metrics_processrO   Úagent.periodic_schedulerrP   r+   ÚappendÚrefresh_tickr%   r*   )r,   rO   rP   s   &  r   ÚstartÚDurableTurnLease.startS   sž   € Ø�Z�Z‹ZØ#ˆDÔ÷ ð 	�
‰
×"Ñ"Ð#6Ô7ÝLÙ�—‘ÔÝ5à×Ñ×!Ñ!¡(¨4×+<Ñ+<¸d×>SÑ>SÓ"TÔUØ�=‰=Ò$Ø×Ñ×%Ñ% d§m¡m×&<Ñ&<Ó&>Ö?ñ %÷ �Zús   •CÃC)	c                ó   <€ V ^8„  d   QhRR/# r7   r8   )r   r   s   "€r   r   r   a   s   ø€ ÷ ñ  ñ r   c                óª   € V P                   ;_uu_ 4        RV n        V P                  P                  4        RRR4       R#   + '       g   i     R# ; i)zÒStop renewal and deactivate the turn. Also the watchdog's deactivate callback: a wedge the
hard interrupt cannot unwind must not keep the lease alive forever; TTL expiry lets
stale-turn cleanup reclaim the row.FN)r'   r(   r#   Úsetr3   s   &r   rI   ÚDurableTurnLease.stop_refreshera   s.   € ð �Z�Z‹ZØ$ˆDÔØ�I‰I�M‰MŒO÷ �Z�ZŠZús   •"AÁA	c                ó$   <€ V ^8„  d   QhRS[ RR/# )r   Útimeoutr   N©r   )r   r   s   "€r   r   r   k   s   ø€ ÷ (ñ (¡Eð (°Dñ (r   c                óP   € V P                    F  pVP                  VR7       K  	  R# )zŒCancel both timers; ``wait=timeout`` mirrors the old ``thread.join(timeout)`` so an
in-flight tick finishes before ``clear_interrupt`` runs.)ÚwaitN)r+   Úcancel)r,   r]   Úhandles   && r   Újoin_threadsÚDurableTurnLease.join_threadsk   s"   € ð ×(Ô(ˆFØ�M‰M˜wˆMÖ'ó )r   c                ó   <€ V ^8„  d   QhRR/# r7   r8   )r   r   s   "€r   r   r   q   s   ø€ ÷ 	@ñ 	@˜ñ 	@r   c                ó>  € V P                   p V P                  P                  V P                  V P                  4       \        VRR4      V P                  8X  d   RVn	        RVn
        R# R#   \
         d&    \        P                  RT P                  RR7        L]i ; i)zWRelease the row and drop the agent's holder attrs (only if they still name this lease).z(Failed to release session turn lease: %sT©Úexc_infoÚ!_active_session_turn_lease_holderN)r   r   Úrelease_session_turn_leaser   r   rD   ÚloggerÚerrorr$   ri   Ú&_active_session_turn_lease_ttl_seconds)r,   r   s   & r   ÚreleaseÚDurableTurnLease.releaseq   s†   € à—
‘
ˆð	eØ�G‰G×.Ñ.¨t¯©ÀÇÁÔLô �5Ð=¸tÓDÈÏÉÔSØ6:ˆEÔ3Ø;?ˆEÖ8ñ Tøô ô 	eÜ�L‰LÐCÀTÇ_Á_Ð_cˆLÖdð	eús   Ž0A, Á,-BÂBc                ó    <€ V ^8„  d   QhRS[ /# r0   ©Úbool)r   r   s   "€r   r   r   |   s   ø€ ÷ $ñ $¡ñ $r   c                ó€   € V P                   ;_uu_ 4        V P                  uuR R R 4       #   + '       g   i     R # ; i)N)r'   r(   r3   s   &r   r@   ÚDurableTurnLease.is_turn_active|   s    € Ø�Z�Z‹ZØ×#Ñ#÷ �Z�Z‹Zús   •,¬=	c                ó$   <€ V ^8„  d   QhRS[ RR/# )r   Úmessager   Nr1   )r   r   s   "€r   r   r   €   s   ø€ ÷ Gñ G¡sð G¨tñ Gr   c                óÂ  € V P                   ;_uu_ 4        V P                  P                  4       '       g   V P                  '       g    RRR4       R# Wn         V P
                  P                  VR\        R7       RRR4       R#   \         d:    RT P
                  n	        YP
                  n
        \        T P
                  n         LMi ; i  + '       g   i     R# ; i)z±Lease-loss interrupts fire UNCONDITIONALLY (no generation claim): a lost lease means
this process no longer owns the session. Only the watchdog's stalls can be spuriously stale.NT)Úhard_cancelÚtool_reason)r'   r#   Úis_setr(   r)   r   Ú	interruptÚ_REASON_LEASE_LOSTrD   Ú_interrupt_requestedÚ_interrupt_messageÚ_tool_interrupt_reason)r,   rv   s   &&r   Ú_interrupt_turnÚ DurableTurnLease._interrupt_turn€   s£   € ð �Z�Z‹ZØ�y‰y×Ñ×!Ò!¨×)9×)9Ð)9Ø÷ ‰Zð &-Ô"ðGØ—
‘
×$Ñ$ W¸$ÔL^Ð$Ô_÷ ‰Zøô ô GØ26�—
‘
Ô/Ø07—
‘
Ô-Ü4F�—
‘
Ö1ðGú÷ �ZˆZús6   •2CÁCÁCÁ"BÂAC
ÃCÃ	C
Ã
CÃC	c                ó&   <€ V ^8„  d   QhRS[ RS[/# )r   rv   r   )r   rr   )r   r   s   "€r   r   r   Ž   s   ø€ ÷ ñ ±sð ¹tñ r   c                óæ  € V P                   pVP                  4       ;_uu_ 4        \        VR^ 4      pV\        VRR4      3VP                  VP                  38w  d    RRR4       R#  RRR4       V P
                  ;_uu_ 4        V P                  P                  4       '       g   V P                  '       g    RRR4       R#  RRR4        VP                  VRRXR7      pVRJ d   R# V P
                  ;_uu_ 4        W n        RRR4       R#   + '       g   i     L®; i  + '       g   i     Lf; i  \         d    \        P                  RRR	7       Rp Lyi ; i  + '       g   i     R# ; i)
aÐ  Commit point for the watchdog's stall observation.

Revalidates the observed ``(generation, timestamp)`` under the SAME lock ``_touch_activity``
uses, so a turn that resumed while the stall was logged is never hard-cancelled; the
revalidated generation is consumed by ``interrupt(require_generation=...)`` with the first
publication in ONE critical section. If ``interrupt`` raises, the abort declines FAIL-CLOSED.
Returns False when stale or already winding down.Ú"_turn_liveness_activity_generationÚ_last_activity_tsNFTzturn liveness watchdog)rx   ry   Úrequire_generationz9Turn liveness abort interrupt raised; declining the abortrg   )r   rG   r$   Ú
generationÚactivity_tsr'   r#   rz   r(   r{   rD   rk   Údebugr)   )r,   Úsnapshotrv   r   Úcurrent_generationÚ	publisheds   &&&   r   rH   Ú&DurableTurnLease.commit_liveness_abortŽ   s7  € ð —
‘
ˆØ×*Ñ*×,Õ,Ü!(¨Ð0TÐVWÓ!XÐØ"¤G¨EÐ3FÈÓ$MÐNØ×#Ñ# X×%9Ñ%9ðSô ð ÷ -Ñ,ð÷ -ð �Z�Z‹ZØ�y‰y×Ñ×!Ò!¨×)9×)9Ð)9Ø÷ ‰ZØ)9÷ ð	ØŸ™Ø TÐ7OØ#5ð (ó ˆIð ˜ÓáØ�Z�Z‹ZØ%,Ô"÷ á÷- -×,ú÷ �Zûô ô 	Ü�L‰LÐTÐ_cˆLÔdØŠIð	ú÷ ŽZáús;   ¥9DÂ2D"Â8D"ÃD5 Ã>EÄD	Ä"D2	Ä5$EÅEÅE0	c                ó   <€ V ^8„  d   QhRR/# r7   r8   )r   r   s   "€r   r   r   ¯   s   ø€ ÷ Bñ B ñ Br   c                óà  € V P                   pV'       g   R# T P                  p^ RIHp \	        VRR4      ;'       g    \        4       ;_uu_ 4        \	        VRR4      V8w  d    RRR4       R# RVn        RVn        \	        VR\        P                  ! 4       4      P                  4        RVn        VP                  e   V! RVP                  4       RRR4       R#   + '       g   i     R# ; i)zUClear only the interrupt admitted by this lease's refresher/watchdog. Run AFTER join.N)Úset_interruptÚ_pending_redirect_lockr~   FÚ_hard_interrupt_requested)r)   r   Útools.interruptr�   r$   r   r}   r~   r!   r"   ÚclearÚ _interrupt_thread_signal_pendingÚ_execution_thread_id)r,   rv   r   Ú_set_interrupts   &   r   Úclear_interruptÚ DurableTurnLease.clear_interrupt¯   s½   € à×(Ñ(ˆßÙØ—
‘
ˆÝCä�UÐ4°dÓ;×LÐL¼{»}×LÑLÜ�uÐ2°DÓ9¸WÔDØ÷ MÑLð */ˆEÔ&Ø'+ˆEÔ$Ü�EÐ6¼	¿ºÓ8IÓJ×PÑPÔRØ5:ˆEÔ2Ø×)Ñ)Ò5Ù˜u e×&@Ñ&@ÔA÷ M×L×LÒLús   ÁCÁ.A$CÃC-	c                ó    <€ V ^8„  d   QhRS[ /# r0   rq   )r   r   s   "€r   r   r   Á   s   ø€ ÷ ñ ©dñ r   c                óp   € \         P                  RV P                  4       4       V P                  R4       R# )zRState.db stayed locked until no renewal can land before the row expires: stop now.zASession turn lease refresh stayed locked through its lifetime: %súNSession turn lease could not be refreshed; stopping to protect the transcript.F)rk   Úwarningr4   r€   r3   s   &r   Ú_stop_on_exhausted_authorityÚ-DurableTurnLease._stop_on_exhausted_authorityÁ   s-   € ä�‰ÐZÐ\`×\tÑ\tÓ\vÔwØ×ÑÐmÔnÙr   c           	     óf  € V P                   P                  4       '       d   R# \        P                  ! 4       pV P                  \        ,
          V,
          pV^ 8:  d   V P                  4       #  V P                  P                  V P                  4       V P                  \        \        \        V4      R7      '       d   V\        ,           V n        R# V P                   P                  4       '       d   R# \        P                  RV P                  4       4       V P                  R4       R#   \          dü   pT P                   P                  4       '       d    Rp?R# ^ RIHp T! T4      '       d€   \        P                  ! 4       T P&                  ,           \        ,           T P                  8¼  d   T P                  4       u Rp?# \        P)                  RT P                  4       4        Rp?R# \        P)                  RT P                  4       R	R
7       T P                  R4        Rp?R# Rp?ii ; i)uô  One periodic renewal (every ``refresh_interval`` via the shared scheduler). A real
miss (rowcount 0) or a non-lock error interrupts the turn. A SQLite lock is a missed
tick only while the next attempt still lands before ``_authority_deadline``. Returning
False stops the timer.

Acquisition reclaims a row once ``expires_at <= now``, even if the old process is
alive. Holder-qualified release does not block that path, so a run of lock errors
must not keep this turn active up to and past the deadline. A successful renewal
is the only thing that moves the deadline.

The holder-qualified UPDATE fences a late refresher from a successor lease. The faÃ§ade's
finally sets ``stop`` before releasing, so a holder-fenced miss observed after stop is not
a loss.F)Úttl_secondsÚ
patience_sNz0Lost session turn lease while turn is active: %sz<Session turn lease lost; stopping to protect the transcript.)Úis_sqlite_lock_errorz<Session turn lease refresh hit a SQLite lock; will retry: %sz(Failed to refresh session turn lease: %sTrg   rœ   )r#   rz   r   r    Ú_REFRESH_EXPIRY_MARGIN_Srž   r   Úrefresh_session_turn_leaser4   r   r   ÚminÚ_REFRESH_WRITE_PATIENCE_Srk   rl   r€   rD   Úhermes_state_errorsr£   r%   r�   )r,   ÚstartedÚpatienceÚexcr£   s   &    r   rU   ÚDurableTurnLease.refresh_tickÇ   s¹  € ð �9‰9×Ñ×ÒÙÜ—)’)“+ˆð ×+Ñ+Ô.FÕFÈÕPˆØ�qŒ=Ø×4Ñ4Ó6Ð6ð!	Ø�w‰w×1Ñ1Ø×(Ñ(Ó*¨D¯K©KÔEVÜÔ8¸(ÓCð 2÷ ò ð ,3Ô5FÕ+F�Ô(ÙØ�y‰y×Ñ×!Ò!ÙÜ�L‰LØBÀD×D\ÑD\ÓD^ôð × Ñ Ð!_Ô`ñ, øô+ ô 	Ø�y‰y×Ñ×!Ò!ÝÝ@á# C×(Ò(ô —9’9“; ×!6Ñ!6Õ6Ô9QÕQÐUY×UmÑUmÔmØ×<Ñ<Ó>Õ>Ü—‘ØRØ×,Ñ,Ó.ôõ Ü�N‰NØ:¸D×<TÑ<TÓ<VÐaeð ô ð × Ñ Ø`÷ð ñ ûð+	úsD   Á.A!D* ÃD* Ã35D* Ä*H0Ä5 H+ÅH+Å/AH+Æ>H0Ç$H+Ç.7H+È+H0)r    r'   r   r   r   r)   r%   r   r#   r+   r(   r*   )ç      ð?)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r-   r4   rK   rV   rI   Údeactivate_after_liveness_abortrc   rn   r@   r€   rH   r˜   rž   rU   Ú__static_attributes__Ú__classdictcell__©r   s   @r   r   r   "   s§   ø‡ € ñð&Ðae÷ &ò &÷"Jð J÷ð ÷*@ð @÷ð ð '5Ð#÷(ò (÷	@ð 	@÷$ð $÷Gð G÷ð ÷BBð B÷$ð ÷9ð 9r   r   c                   ó<   a € ] tR tRt o RtRtRtRtV 3R ltRt	V t
R# )ÚTurnLeaseAdmissioni  z`Outcome of ``admit_durable_turn_lease``: exactly one of ``lease`` / ``early_result`` may be set.Nc                óª   <€ V ^8„  d   Qh/ S[ S[,          ;R&   S[ S[S[S[3,          ,          ;R&   S[ S[S[S[S[3,          ,          ,          ;R&   # )r   ÚleaseÚearly_resultÚconversation_history)r   r   Údictr   r   Úlist)r   r   s   "€r   r   ÚTurnLeaseAdmission.__annotate__  sQ   ø‡ ‚ ñ Ñ$Õ%Ñ,ñ	 ñ
 ™4¡¡S �>Õ*Ñ1ñ ñ #¡4©©S±#¨X­Õ#7Õ8Ñ?ò r   r8   )r®   r¯   r°   r±   r²   rº   r»   r¼   Ú__annotate_func__r´   rµ   r¶   s   @r   r¸   r¸     s   ø‡ € ájà(,€EØ-1€LØ;?Ð÷ ƒ r   r¸   c                óH   € V ^8„  d   QhR\         R\         R\        R\        /# )r   r   r   Úfloorr   )r   r   )r   s   "r   r   r     s(   € ÷ %ñ %¬Cð %¼ð %ÄUð %Ìuñ %r   c                ó<  € \        V RR4      p\        V4      '       d?    V! W4      p\        V\        \        34      '       d   \	        V4      #  V\        ,           # V\        ,           #   \
         d'    \        P                  RRR7        T\        ,           # i ; i)zñThe admitted row's committed ``expires_at``; when unreadable, ``floor + TTL`` (taken before
acquisition, so never later than the real expiry). Overstating it lets a successor reclaim the
row while this turn still believes it holds the lease.Úsession_turn_lease_expires_atNzJCould not read the admitted turn lease expiry; using the pre-acquire floorTrg   )	r$   ÚcallableÚ
isinstanceÚintr   rD   rk   r‰   r   )r   r   r   rÂ   ÚreaderÚ	committeds   &&&&  r   Ú_committed_lease_expiryrÊ     s™   € ô �RÐ8¸$Ó?€FÜ�×Òð	vÙ˜zÓ2ˆIÜ˜)¤c¬5 \×2Ò2Ü˜YÓ'Ð'ð 3ð Ô$Õ$Ð$ˆ5Ô$Õ$Ð$øô ô 	vÜ�L‰LÐeÐptˆLÕuØÔ$Õ$Ð$ð	vús    .A* Á*"BÂBc                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   r   r   )r   r   rr   )r   s   "r   r   r     s   € ÷ ñ ¬Cð ´H¼TµNñ r   c                ó|   €  V P                  V4      RJ#   \         d    \        P                  RRR7        R# i ; i)zVTrue / False when the row read answered; None when it failed and the state is unknown.NzPCould not check durable session after turn lease admission; row state is unknownTrg   )Úget_sessionrD   rk   r�   )r   r   s   &&r   Ú_durable_session_existsrÎ     sH   € ð	Ø�~‰~˜jÓ)°Ð5Ð5øÜô ô 	�‰Ø^Øð 	ô 	
ò ðús   ‚ •";º;c                óÄ   € V ^8„  d   QhR\         R\         R\        \         \        3,          R\        \        \        \         \        3,          ,          ,          R\
        /# )r   r   Úrelay_turn_idÚtask_contextr¼   r   )r   r½   r   r   r¾   r¸   )r   s   "r   r   r   )  sW   € ÷ kñ kÜðkÜ.1ðkÜAEÄcÌ3ÀhÅðkä"¤4¬¬S´#¨X­Õ#7Õ8ðkô ñkr   c               ób  a aaa€ \        S RR4      p\        VR7      pVe	   V'       g   V# \        S RR4      '       g&   \        \        \        V4      RR4      4      '       g   V# R\        P
                  ! 4        \        4        RT R	VR
,          ;'       g    R 2pR;ooR V3R llpR V VV3R llp	\        P                  ! 4       p
VP                  W\        \        W˜V 3R lR7      '       g   \        S WSR7      Vn        V# \        S WQV\        WQWz4      R7      pVS n        \        S n         \#        WQ4      pV'       d   RS n        S'       d£   VRJd�   S'       d   S P'                  R4       VP)                  V4      pV'       d   VS n        WÓR&   VP-                  S P*                  RRR7      pV'       g	   V'       d2   ^ RIHo TP3                  V3R lT;'       g    .  4       4       Wæn        VP7                  4        Y¶n        T#   \8         d    TP;                  4        h i ; i)aD  Acquire the session turn lease (the row need not exist yet); build (not start) its threads.

Mutates ``task_context["session_id"]`` and ``agent.session_id`` when the wait forced a resume-id
reload. Returns an ``early_result`` (interrupted / timed out) instead of a lease when admission
fails; the caller returns it verbatim.Ú_session_dbN)r¼   Ú_persist_disabledFÚacquire_session_turn_leasezpid=z:turn=z
:platform=ÚplatformÚunknownc                ó   € V ^8„  d   QhRR/# r7   r8   )r   s   "r   r   Ú.admit_durable_turn_lease.<locals>.__annotate__G  s   € ÷ ñ ˜4ñ r   c                  ó   <€ R o R# )TNr8   )Úreload_neededs   €r   Ú_on_contendedÚ/admit_durable_turn_lease.<locals>._on_contendedG  s
   ø€ ð
 Šr   c                ó(   € V ^8„  d   QhR\         RR/# )r   Úelapsedr   Nr^   )r   s   "r   r   rÙ   N  s   € ÷ 
ñ 
œ%ð 
 Dñ 
r   c                 ój   <€ R ;ooSP                  V R8  d	   R4       R# R\        V 4       R24       R# )Tr­   ug   â�³ Another Hermes process is using this session; waiting for it to finish before starting your turn...u@   â�³ Still waiting for the other Hermes process on this session (zs)...N)Ú_emit_statusrÇ   )rß   r   Ú	announcedrÛ   s   &€€€r   Ú_on_waitÚ*admit_durable_turn_lease.<locals>._on_waitN  sD   ø€ à$(Ð(ˆ˜	Ø×Ñð ˜Œ}ðDö	
ð OÌsÐSZË|ÈnÐ\aÐbö		
r   c                  ó   <€ \        S R R4      # )r}   F)r$   )r   s   €r   Ú<lambda>Ú*admit_durable_turn_lease.<locals>.<lambda>\  s   ø€ œW UÐ,BÀEÔJr   )r¡   Úwait_secondsÚon_waitÚon_contendedÚshould_abort)Úwaited)r   Tz1Session is free; loading the latest transcript...r   )Úrepair_alternationÚinclude_row_ids©Ú"_PERSIST_AFTER_ADMISSION_INTERRUPTc              3   óœ   <"  € T FA  p\        V\        4      '       g   K  VP                  S4      '       g   K4  R V9  g   K=  Vx € KC  	  R# 5i)Ú_row_idN)rÆ   r½   Úget)Ú.0Úmrð   s   & €r   Ú	<genexpr>Ú+admit_durable_turn_lease.<locals>.<genexpr>ˆ  sC   øé € ð  Ù :˜!Ü! !¤T×*ô Ø/0¯u©uÐ5W×/Xô à!¨Ñ*÷ ’AÓ :ùs   ƒA A¹AÁ
A)r$   r¸   rÅ   ÚtypeÚosÚgetpidr   r   rÕ   r   ÚLEASE_WAIT_SECONDSÚ_lease_not_acquired_resultr»   r   rÊ   ri   rm   rÎ   Ú_session_db_createdrá   Úresolve_resume_session_idr   Úget_messages_as_conversationÚagent.session_persistencerð   Úextendr¼   rK   ÚBaseExceptionrn   rº   )r   r   rÐ   rÑ   r¼   r   Ú	admissionr   rÜ   rã   Úauthority_floorrº   ÚdurableÚlatest_session_idÚreloadedrð   râ   rÛ   s   f$$$$          @@@r   Úadmit_durable_turn_leaser  )  s-  û€ ô 
�˜ tÓ	,€BÜ"Ð8LÔM€IØ	‚zŸØÐô 	�Ð*¨E×2Ò2Üœ¤ R£Ð*FÈÓM×NÒNàÐð Œr�yŠy‹{ˆmÔ2Ó4Ð5°V¸M¸?Ø
�\ *Õ-×:Ð:°Ð;ð	=ð ð !&Ð%€M�I÷ð ÷
ò 
ô —i’i“k€OØ×(Ñ(ØÔ(9ÔHZØÜJð )÷ ò ô
 "<¸EÀ:ØCLô"Nˆ	ÔàÐô Øˆr˜vÔ2IÈ"ÐZ`Ó2rô€Eð /5€EÔ+Ü3D€EÔ0ð)ô *¨"Ó9ˆßð )-ˆEÔ%÷
 ˜W¨EÓ1ßØ×"Ñ"Ð#VÔWð !#× <Ñ <¸ZÓ HÐß Ø#4�Ô Ø->˜\Ñ*Ø×6Ñ6Ø× Ñ °TÈ4ð 7ó ˆH÷
 Ÿ(õ YØ—‘ô  Ø 4× :Ð :¸Ð :ó ô ð
 2:Ô.Ø×ÑÔð
 „OØÐøô ô à�‰ŒØðús0   Ä5!H ÅH Å%)H Æ0H Ç H ÇH Ç'"H ÈH.c                ó  € V ^8„  d   QhR\         \        \        3,          R\        R\        R\        \        ,          R\        \        ,          R\        \         \        \        3,          ,          R\        \        ,          RR	/# )
r   r»   Úuser_messageÚpersist_user_messageÚ	timestampÚdisplay_kindÚdisplay_metadataÚplatform_idr   N)r½   r   r   r   r   )r   s   "r   r   r   —  s€   € ÷ Qñ QÜ”sœC�x•.ðQÜ03ðQÜKNðQäœ�ðQä.6´s­mðQäOWÔX\Ô]`ÔbeÐ]eÕXfÕOgðQô œ#•ðQð 
ñ	Qr   c               óª  € V P                  RR4      pV'       g   V P                  R4      '       d   VR9   d   R# ^ RIHp ^ RIHp	 Tp
Ve/   \        V\        4      '       d   \        V\        4      '       d   Tp
RRR	W©R
/p\        V\        4      '       d   W8w  d   WR&   V'       d   WKR&   V'       d   W[R&   Ve   WkR&   V! V R,          W³R7       R# )a=  A follow-up that interrupted the lease wait must not consume the accepted input: append it to
the early result's history so the follow-up turn sees it and persists it (the flush honours
``_PERSIST_AFTER_ADMISSION_INTERRUPT`` because this turn never owned the lease). A hard stop
(``/stop``) cancels the input instead.Ú_hard_interruptedFÚinterruptedN)Úappend_messagerï   ÚroleÚuserÚcontentTÚapi_contentr  r  Úplatform_message_idÚmessages)r  )NÚ )	Úpopró   Úagent.message_metadatar  r   rð   rÆ   r¾   r   )r»   r
  r  r  r  r  r  Úhard_interruptedr  rð   Údurable_contentÚdeferred_users   &&&$$$$     r   Úcarry_unadmitted_user_messager   —  sÊ   € ð $×'Ñ'Ð(;¸UÓCÐß˜|×/Ñ/°×>Ò>À,ÐR\ÔB\ÙÝ5ÝLà"€OØÒ'Ü�|¤T×*Ò*¬jÐ9MÌt×.TÒ.Tà.ˆà�˜	 ?ÐX\ð%€Mô �,¤×$Ò$¨Ô)HØ'3�mÑ$ßØ(4�nÑ%ßØ,<Ð(Ñ)ØÒØ/:Ð+Ñ,Ù�< 
Õ+¨]×Pr   c                ó^   € V ^8„  d   QhR\         R\        R\        \         \        3,          /# )r   r   rì   r   )r   rr   r½   r   )r   s   "r   r   r   ¹  s/   € ÷ 2ñ 2´#ð 2ÔX\ð 2ÔaeÔfiÔknÐfnÕaoñ 2r   c          	     óÈ  € R\        T;'       g    . 4      R^ RR/p\        V RR4      '       d±   \        P                  RV4       \        V RR4      p\	        \        \        VR	R4      4      ;'       d    VP                  4       4      pR
V'       d   RMR/VCRR/CpV'       d   RVR&   \        V RR4      '       d   V P                  VR&    V P                  4        V# Rp\        P                  RV4        V P                  V4       R
V/VCRRRRV 2RRRR/C#   \         d    RT n
        RT n         T# i ; i  \         d    \        P                  RRR7        LWi ; i)z­``waited``: another holder was seen (the user was told so), not merely an interrupt that
landed before the first acquisition attempt, which no other process was involved in.r  Ú	api_callsÚ	completedFr}   z0session turn lease wait aborted by interrupt: %sr’   Nrz   Úfinal_responsez[Stopped waiting for another Hermes process on this session. Your message was not processed.zAStopped before this turn started. Your message was not processed.r  Tr  r~   r)   u–   â�³ Another Hermes process kept this session busy too long. Your message was not processed - wait for the other process to finish, then send it again.z(session turn lease wait timed out for %sz1Failed to emit session turn lease timeout warningrg   Úfailedrl   zsession_turn_lease_timeout:Úfailure_reasonÚsession_busyÚfailure_retryable)r¾   r$   rk   Úinforr   rÅ   rz   r~   r˜   rD   r}   rl   Ú_emit_warningr‰   )	r   r   r¼   rì   ÚbaseÚ
hard_eventr  ÚresultÚtimeout_msgs	   &&&$     r   rü   rü   ¹  s±  € ð œÐ1×7Ð7°RÓ8¸+ÀqÈ+ÐW\Ð]€DÜˆuÐ,¨e×4Ò4Ü�‰ÐFÈ
ÔSÜ˜UÐ$?ÀÓFˆ
ÜÜ”W˜Z¨°4Ó8Ó9×QÐQ¸j×>OÑ>OÓ>Qó
Ðð ÷ ñ2ð Tð	
ð ð	
ð ˜4ñ	
ˆ÷ Ø*.ˆFÐ&Ñ'Ü�5Ð.°×5Ò5Ø*/×*BÑ*BˆFÐ&Ñ'ð	,Ø×!Ñ!Ô#ð ˆð	Pð ô ‡L�LÐ;¸ZÔHðYØ×Ñ˜KÔ(ð
 	˜+ðà
ðð 	�$ØÐ.¨z¨lÐ;Ø˜.Ø˜Tñð øô ô 	,Ø).ˆEÔ&Ø'+ˆEÕ$Øˆð	,ûô ô YÜ�‰ÐHÐSWˆÖXðYús$   ÃD Ã8D< ÄD9Ä8D9Ä<"E!Å E!)r²   Úloggingrù   r!   r   Ú
contextlibr   Údataclassesr   Útypingr   r   r   r   Úhermes_state_pidnsr   Ú	getLoggerrk   r|   r   rû   r§   r¤   r   r¸   rÊ   rÎ   r  r   rü   r8   r   r   Ú<module>r6     sŸ   ðñó Û 	Û Û Ý "Ý !ß ,Ó ,å 5ð 
×	Ò	˜;Ó	'€ð /Ð àÐ ØÐ à Ð àÐ ÷^ñ ^ðB ÷@ð @ó ð@õ%õõkõ\Q÷D2r   