
    epj                    X    d Z ddlmZ ddlZddlmZmZmZ ddZddZ	ddZ
ddddZdS )ub  Gateway session stall notification policy (#72016 item 2).

Consumes the shared activity observation contract from
``agent.session_activity`` / ``AIAgent.get_activity_summary()``
(#72039) as the **single progress source**. This module owns only the
notify-once policy for "pending inbound + stale progress"; it does not
invent a parallel progress clock from turn-start or inbound event
timestamps.

Boundaries (keep separate):
- ``gateway/shutdown_watchdog.py`` — process / event-loop liveness
- ``gateway/delivery_ledger.py`` — outbound delivery obligations
- Pending inbound here is a stall *policy gate* (queued follow-up exists),
  not an outbound obligation and not a progress timestamp.

Notification / timeout / kill / retry policy stay in their own components;
the shared contract remains observation-only (timestamp + bounded
description + provenance).
    )annotationsN)AnyMappingOptionaltimeout_secondsfloatidle_secondsOptional[float]has_pending_inboundboolalready_notifiedreturnc                6    | dk    rdS |sdS |rdS |dS || k    S )zAReturn True when a stall warning should be sent for this session.r   F )r   r	   r   r   s       ;/home/thesage/.hermes/hermes-agent/gateway/session_stall.py&should_emit_session_stall_notificationr      sD     !u u uu?**    c                .    |sdS | dk    rdS |dS || k     S )zEReturn True when a prior stall notice may be cleared (episode ended).Tr   NFr   )r   r	   r   s      r   'should_clear_session_stall_notificationr   .   s7      t!tu/))r   strc                N    t          dt          | dz                      }d| dS )zEUser-facing stall warning (ASCII minutes; matches issue #72016 copy).   <   u4   ⚠️ Agent session appears stalled (last activity z min ago). Try /new to reset.)maxint)r	   minss     r   !format_session_stall_notificationr   ?   s9    q#lb())**D	t 	 	 	r   )nowactivityOptional[Mapping[str, Any]]r   c               2   | sdS |                      d          }|H	 t          |          }t          j        |          r
|dk     rdS |S n# t          t
          f$ r d}Y nw xY w|                      d          }||                      d          }|dS 	 t          |          }n# t          t
          f$ r Y dS w xY wt          j        |          sdS |&ddl}t          |                                          }nt          |          }||z
  }|dk     rdS |S )u^  Idle seconds from a shared activity snapshot only (#72039 contract).

    Prefers ``seconds_since_activity`` when present and finite; otherwise
    derives from ``last_activity_at`` / ``last_activity_ts``. Returns
    ``None`` when there is no usable progress timestamp — callers must
    not fall back to turn-start or pending-inbound clocks.
    Nseconds_since_activityr   g        last_activity_atlast_activity_ts)getr   mathisfinite	TypeError
ValueErrortime)r   r   elapsedidletswhen_timeclocks           r   *resolve_session_idle_seconds_from_activityr1   H   sd     tll344G	>>D }T"" !883 :& 	 	 	DDD	 
(	)	)B	z\\,--	ztRyyz"   tt= t
{ejjll##c

4<DaxxsKs#   A A! A!B% %B:9B:)
r   r   r	   r
   r   r   r   r   r   r   )r   r   r	   r
   r   r   r   r   )r	   r   r   r   )r   r    r   r
   r   r
   )__doc__
__future__r   r&   typingr   r   r   r   r   r   r1   r   r   r   <module>r5      s    ( # " " " " "  ) ) ) ) ) ) ) ) ) )+ + + +&* * * *"     1 1 1 1 1 1 1 1r   