+
    iHàj}  ã                   ó’   € 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
 ]P                  ! R4      tR R lt ! R R	4      tR# )
a  Turn-liveness activity tracking for ``AIAgent`` (gateway watchdog + session activity persistence).

``_touch_activity`` is the single write path; persistence is rate-limited and never raises.
Extracted from ``run_agent.py``; every method resolves through ``AIAgent``'s MRO unchanged.
N)Úsuppress)ÚOptional)ÚActivityProvenanceÚ	run_agentc                ó8   € V ^8„  d   QhR\         P                  /# ©é   Úreturn©Ú	threadingÚLock)Úformats   "Ú</home/ubuntu/.hermes/hermes-agent/agent/activity_tracking.pyÚ__annotate__r      s   € ÷ ñ œ9Ÿ>™>ñ ó    c                ó^   € \        V RR4      pVf   \        P                  ! 4       pWn        V# )zaLazy per-instance ``_turn_liveness_activity_lock`` (so ``__new__``/SimpleNamespace doubles work).Ú_turn_liveness_activity_lockN)Úgetattrr   r   r   )ÚobjÚ_locks   & r   Ú_activity_lockr      s-   € ä�CÐ7¸Ó>€EØ‚}Ü—’Ó ˆØ+0Ô(Ø€Lr   c                   óx   a € ] tR t^t o RtV 3R lR ltRRRR/V 3R lR	 lltV 3R
 lR ltV 3R lR ltRt	V t
R# )ÚActivityTrackingMixinzILiveness timestamps/labels and rate-limited session activity persistence.c                ó4   <€ V ^8„  d   QhRS[ P                  /# r   r
   )r   Ú__classdict__s   "€r   r   Ú"ActivityTrackingMixin.__annotate__   s   ø€ ÷ $ñ $©¯©ñ $r   c                ó   € \        V 4      # )a3  Shared lock for the activity clock and its generation counter.

``_touch_activity`` stamps under it and the liveness watchdog samples/commits under it, so a stall
observation can never abort a turn that resumed in between.

Created lazily so ``AIAgent.__new__``-based test doubles keep working. See #95663.
)r   )Úselfs   &r   Ú_liveness_activity_lockÚ-ActivityTrackingMixin._liveness_activity_lock   s   € ô ˜dÓ#Ð#r   Ú
provenanceNÚforce_persistFc                ó@   <€ V ^8„  d   QhRS[ RS[S[,          RS[RR/# )r   Údescr    r!   r	   N)Ústrr   r   Úbool)r   r   s   "€r   r   r   )   s5   ø€ ÷ 00ñ 00Ùð00Ù(0Ñ1CÕ(Dð00áð00ð 
ñ00r   c               ó`  € ^ RI HpHpHpHp V! V4      p\        V 4      ;_uu_ 4        \        V R^ 4      ^,           V n        \        P                  ! 4       V n	        V! V4      V n
        W€n        RV n        RRR4       \        P                  P                  R4      '       d8   \!        \"        4      ;_uu_ 4        ^ RIHp	Hp
 V	! 4        V
! V 4       RRR4       V'       g   V! V4      '       d	   V! V 4       V P+                  4        R#   + '       g   i     Lœ; i  + '       g   i     LS; i)uf  Update the last-activity timestamp and description (thread-safe).

Bumps a monotonic generation under the activity lock so the watchdog can bind a stall observation to
the exact ``(generation, timestamp)`` it sampled. Also bridges (rate-limited, best-effort) to the
kanban heartbeat when this is a dispatcher-spawned worker, and to the durable SessionDB activity
projection. ``provenance`` names special writers (compression); ``force_persist`` bypasses the
SessionDB rate limit â€” as does any terminal compression provenance, which must converge the durable
row at once (nothing writes after it). Module-level lock helper, not ``self._liveness_activity_lock()``:
doubles bind only ``_touch_activity`` (tests/agent/test_session_activity_persist.py).

Bridge is rate-limited (60s) and best-effort â€” it never raises into the agent loop. See #31752.
See #72016, #72039.
)Úbound_activity_descriptionÚ"is_terminal_compression_provenanceÚnormalize_activity_provenanceÚ%reset_session_activity_persist_windowÚ"_turn_liveness_activity_generationNÚHERMES_KANBAN_TASK)Ú!heartbeat_current_worker_from_envÚinject_new_comments_from_env)Úagent.session_activityr'   r(   r)   r*   r   r   r+   ÚtimeÚ_last_activity_tsÚ_last_activity_descÚ_last_activity_provenanceÚ_turn_liveness_abort_claimÚosÚenvironÚgetr   Ú	ExceptionÚtools.kanban_toolsr-   r.   Ú _persist_session_activity_if_due)r   r#   r    r!   r'   r(   r)   r*   Úresolved_provenancer-   r.   s   &&$$       r   Ú_touch_activityÚ%ActivityTrackingMixin._touch_activity)   sä   € ÷"	
ó 	
ñ
 <¸JÓGÐÜ˜D×!Õ!ä˜ÐBÀAÓFÈÕJð Ô3ô &*§Y¢Y£[ˆDÔ"Ù'AÀ$Ó'GˆDÔ$Ø-@Ô*ð /3ˆDÔ+÷ "ô �:‰:�>‰>Ð.×/Ò/äœ)×$Õ$÷ñ 2Ô3á,¨TÔ2÷ %÷ Ñ>Ð?R×SÒSñ
 2°$Ô7Ø×-Ñ-Ö/÷3 "×!ú÷ %×$ús   ¨AD
Â:DÄ
D	ÄD-	c                ó   <€ V ^8„  d   QhRR/# ©r   r	   N© )r   r   s   "€r   r   r   [   s   ø€ ÷ %]ñ %]°$ñ %]r   c                óì  € \        V RR4      p\        V RR4      pV'       d   Vf   R# \        VRR4      p\        V4      '       g   R# ^ RIHpHp \
        P                  ! 4       p\        V RR4      pV'       d   Wg,
          V8  d   R# Y`n        ^ RIH	p  V! VV\        V R	R4      \        V R
R4      V! \        V RR4      4      R7       R#   \         d    \        P                  RRR7        R# i ; i)zÙBest-effort durable activity heartbeat for SessionDB consumers.

Cadence pinned by ``SESSION_ACTIVITY_HEARTBEAT_MIN_INTERVAL_SECONDS`` (config-independent). Fail-open:
a failed write never raises into the agent loop.
Ú
session_idNÚ_session_dbÚtouch_session_activity)Ú/SESSION_ACTIVITY_HEARTBEAT_MIN_INTERVAL_SECONDSr)   Ú#_session_activity_last_persist_monog        ©Úcall_off_event_loopr1   r2   r3   )Údescriptionr    z1session activity heartbeat write failed (ignored)T)Úexc_info)r   Úcallabler/   rE   r)   r0   Ú	monotonicrF   Úagent.runtime_session_storerH   r8   ÚloggerÚdebug)	r   rB   Ú
session_dbÚtouchrE   r)   Únow_monoÚ	last_monorH   s	   &        r   r:   Ú6ActivityTrackingMixin._persist_session_activity_if_due[   sì   € ô ˜T <°Ó6ˆ
Ü˜T =°$Ó7ˆ
ß˜ZÒ/ÙÜ˜
Ð$<¸dÓCˆÜ˜�ŠÙ÷	
ô —>’>Ó#ˆÜ˜DÐ"GÈÓMˆ	÷ ˜(Õ.Ð2aÔaÙØ3;Ô0ÝCð	]ÙØØÜ˜Ð1°4Ó8Ü# DÐ*?ÀÓFÙ8Ü˜DÐ"=¸tÓDó÷øô ô 	]ä�L‰LÐLÐW[ˆL×\ð	]ús   Â4C Ã"C3Ã2C3c                ó   <€ V ^8„  d   QhRR/# r?   r@   )r   r   s   "€r   r   r   ‚   s   ø€ ÷ 3ñ 3°4ñ 3r   c                óR  € RV n         \        P                  V n        \	        V RR4      p\	        V RR4      pV'       d   Vf   R# \	        VRR4      p\        V4      '       g   R# ^ RIHp \        \        4      ;_uu_ 4        V! W14       RRR4       R#   + '       g   i     R# ; i)a  Drop mid-turn activity labels once the turn is no longer running.

Keeps ``_last_activity_ts`` so idle/watchdog clocks stay continuous across turns; clears description +
provenance so idle agents / SessionDB listings stop advertising the last mid-turn stamp.

See #15654, #72039.
Ú rB   NrC   Úclear_session_activity_labelsrG   )
r2   r   ÚUNKNOWNr3   r   rK   rM   rH   r   r8   )r   rB   rP   ÚclearrH   s   &    r   Ú!_reset_activity_labels_after_turnÚ7ActivityTrackingMixin._reset_activity_labels_after_turn‚   s�   € ð $&ˆÔ Ü);×)CÑ)CˆÔ&Ü˜T <°Ó6ˆ
Ü˜T =°$Ó7ˆ
ß˜ZÒ/ÙÜ˜
Ð$CÀTÓJˆÜ˜�ŠÙÝCÜ”i× Õ Ù Ô2÷ !× × Ò ús   Â	BÂB&	)r2   r3   r1   rF   r4   r+   )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r<   r:   r[   Ú__static_attributes__Ú__classdictcell__)r   s   @r   r   r      sD   ø‡ € ÙS÷$ð $ð00ØGKð00à#÷00ò 00÷d%]ð %]÷N3ö 3r   r   )ra   Úloggingr5   r   r0   Ú
contextlibr   Útypingr   r/   r   Ú	getLoggerrN   r   r   r@   r   r   Ú<module>rh      sD   ðñó
 Û 	Û Û Ý Ý å 5ð 
×	Ò	˜;Ó	'€õ÷y3ó y3r   