Ë
    áß²j  ã                   óŒ   — d Z ddlZddlZddlZddlZddlmZ ddlmZ ddl	m
Z
  ej                  d«      Zd
d„Z G d„ d	«      Zy)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                 óZ   — t        | dd«      }|€t        j                  «       }|| _        |S )zaLazy per-instance ``_turn_liveness_activity_lock`` (so ``__new__``/SimpleNamespace doubles work).Ú_turn_liveness_activity_lockN)ÚgetattrÚ	threadingÚLockr   )ÚobjÚ_locks     ú</home/ubuntu/.hermes/hermes-agent/agent/activity_tracking.pyÚ_activity_lockr      s/   € ä�CÐ7¸Ó>€EØ€}Ü—‘Ó ˆØ+0ˆÔ(Ø€Ló    c            	       óN   — e Zd ZdZdd„Zdddœdedee   d	eddfd
„Z	dd„Z
dd„Zy)ÚActivityTrackingMixinzILiveness timestamps/labels and rate-limited session activity persistence.Úreturnc                 ó   — t        | «      S )aS  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_lockz-ActivityTrackingMixin._liveness_activity_lock   s   € ô ˜dÓ#Ð#r   NF)Ú
provenanceÚforce_persistÚdescr   r   c                óÞ  — ddl m}m}m} t	        | «      5  t        | dd«      dz   | _        t        j                  «       | _         ||«      | _	         ||«      | _
        d| _        ddd«       t        j                  j                  d«      r/t        t         «      5  ddlm}m}  |«         || «       ddd«       |r || «       | j)                  «        y# 1 sw Y   ŒrxY w# 1 sw Y   Œ0xY w)u7  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. 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.
        r   )Úbound_activity_descriptionÚnormalize_activity_provenanceÚ%reset_session_activity_persist_windowÚ"_turn_liveness_activity_generationé   NÚHERMES_KANBAN_TASK)Ú!heartbeat_current_worker_from_envÚinject_new_comments_from_env)Úagent.session_activityr   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!   r"   s	            r   Ú_touch_activityz%ActivityTrackingMixin._touch_activity)   s×   € ÷ 	
ñ 	
ô
 ˜DÓ!ñ 		3ä˜ÐBÀAÓFÈÑJð Ô3ô &*§Y¡Y£[ˆDÔ"Ù'AÀ$Ó'GˆDÔ$Ù-JÈ:Ó-VˆDÔ*ð /3ˆDÔ+÷		3ô �:‰:�>‰>Ð.Ô/äœ)Ó$ñ 3÷ñ 2Ô3á,¨TÔ2÷3ñ Ù1°$Ô7Ø×-Ñ-Õ/÷+		3ð 		3ú÷3ð 3ús   –ACÂC#ÃC Ã#C,c                 óš  — t        | dd«      }t        | dd«      }|r|€yt        |dd«      }t        |«      syddlm}m} t        j                  «       }t        | dd«      }||z
  |k  ry|| _        	  ||t        | d	d«      t        | d
d«       |t        | dd«      «      ¬«       y# t        $ r t        j                  dd¬«       Y yw xY w)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_activityr   )Ú/SESSION_ACTIVITY_HEARTBEAT_MIN_INTERVAL_SECONDSr   Ú#_session_activity_last_persist_monog        r%   r&   r'   )Údescriptionr   z1session activity heartbeat write failed (ignored)T)Úexc_info)r	   Úcallabler#   r4   r   r$   Ú	monotonicr5   r,   ÚloggerÚdebug)r   r1   Ú
session_dbÚtouchr4   r   Únow_monoÚ	last_monos           r   r.   z6ActivityTrackingMixin._persist_session_activity_if_dueU   sä   € ô ˜T <°Ó6ˆ
Ü˜T =°$Ó7ˆ
Ù˜ZÐ/ØÜ˜
Ð$<¸dÓCˆÜ˜ŒØ÷	
ô —>‘>Ó#ˆÜ˜DÐ"GÈÓMˆ	Ø�yÑ Ð$SÒSØØ3;ˆÔ0ð	]ÙØÜ˜Ð1°4Ó8Ü# DÐ*?ÀÓFÙ8Ü˜DÐ"=¸tÓDóö	øô ò 	]ä�L‰LÐLÐW[ˆLÖ\ð	]ús   Á33B' Â' C
Ã	C
c                 ó  — d| _         t        j                  | _        t	        | dd«      }t	        | dd«      }|r|€yt	        |dd«      }t        |«      syt        t        «      5   ||«       ddd«       y# 1 sw Y   yxY w)a8  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.
        Ú r1   Nr2   Úclear_session_activity_labels)r&   r   ÚUNKNOWNr'   r	   r8   r   r,   )r   r1   r<   Úclears       r   Ú!_reset_activity_labels_after_turnz7ActivityTrackingMixin._reset_activity_labels_after_turnx   s   € ð $&ˆÔ Ü);×)CÑ)CˆÔ&Ü˜T <°Ó6ˆ
Ü˜T =°$Ó7ˆ
Ù˜ZÐ/ØÜ˜
Ð$CÀTÓJˆÜ˜ŒØÜ”iÓ ñ 	Ù�*Ô÷	÷ 	ñ 	ús   Á$	A6Á6A?©r   zthreading.Lock)r   N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Ústrr   r   Úboolr/   r.   rE   © r   r   r   r      sN   „ ÙSó$ð HLØ#ò*0Øð*0Ø(0Ð1CÑ(Dð*0àð*0ð 
ó*0óX!]ôFr   r   rF   )rJ   Úloggingr)   r
   r$   Ú
contextlibr   Útypingr   r#   r   Ú	getLoggerr:   r   r   rM   r   r   ú<module>rR      sF   ðñó
 Û 	Û Û Ý Ý å 5ð 
ˆ×	Ñ	˜;Ó	'€ó÷nò nr   