
    oq'jH%                    X   d Z ddlmZ ddl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mZ ddlmZ  ej        e          Zd6d7dZd8dZd9dZd:dZd:dZd:dZ G d d          Zd;dZd<d!Zd=d$Zd>d%Zd?d@d(ZdAd)Z e	 G d* d+                      Z!dd,dBd2Z"dCd4Z#dDd5Z$dS )EzCross-process active chat session leases.

The session database records persisted conversations.  This module records
currently open chat surfaces, including idle CLI/TUI sessions that have not
written a transcript row yet.
    )annotationsN)	dataclass)Path)AnyOptionalget_hermes_homemax_concurrent_sessionsvaluer   keystrreturnOptional[int]c                   | dS t          | t                    rt                              d||            dS 	 t          | t                    r3|                                 st          |           t          |           }nGt          | t                    r#t          | 	                                d          }nt          |           }n4# t          t          f$ r  t                              d||            Y dS w xY w|dk    rdS |S )z=Return a positive integer cap, or None when disabled/invalid.NzEIgnoring invalid %s=%r (expected a positive integer; 0/null disables)
   r   )
isinstanceboolloggerwarningfloat
is_integer
ValueErrorintr   strip	TypeError)r   r   parseds      ?/home/ubuntu/.hermes/hermes-agent/hermes_cli/active_sessions.pycoerce_max_concurrent_sessionsr      s   }t% S	
 	
 	

 teU## 	 ##%% ( '''ZZFFs## 	 ++FFZZFz"   S	
 	
 	

 tt {{tMs   BC	 	-C:9C:configc                0   d}d}t          | t                    r\d| v r|                     d          }nS|                     d          }t          |t                    r|                    d          }d}nt          | dd          }t	          ||          S )zBResolve top-level max_concurrent_sessions with gateway.* fallback.Nr
   gatewayzgateway.max_concurrent_sessions)r   )r   dictgetgetattrr   )r   rawr   gateway_cfgs       r   resolve_max_concurrent_sessionsr'   8   s    C
#C&$ 	?$..**677CC **Y//K+t,, 8!oo&?@@7f7>>)#37777    active_countr   max_sessionsc                    d|  d| dS )Nz'Hermes is at the active session limit (/z+). Try again when another session finishes. )r)   r*   s     r   active_session_limit_messager.   I   s)    	3, 	3 	3 	3 	3 	3r(   r   c                 $    t                      dz  S )Nruntimer   r-   r(   r   
_state_dirr1   P   s    y((r(   c                 $    t                      dz  S )Nzactive_sessions.jsonr1   r-   r(   r   _state_pathr4   T       <<000r(   c                 $    t                      dz  S )Nzactive_sessions.lockr3   r-   r(   r   
_lock_pathr7   X   r5   r(   c                  "    e Zd ZddZd Zd ZdS )	_FileLockpathr   c                "    || _         d | _        d S N)r:   _fh)selfr:   s     r   __init__z_FileLock.__init__]   s    	r(   c                   | j         j                            dd           t          | j         d          | _        t
          j        dk    r	 dd l}| j                            d           |	                    | j        
                                |j        d           n# t          $ r5}| j                                         d | _        t          d          |d }~ww xY w	 dd l}|                    | j        
                                |j                   nB# t          $ r5}| j                                         d | _        t          d          |d }~ww xY w| S )NTparentsexist_okza+bntr      z$active session file lock unavailable)r:   parentmkdiropenr=   osnamemsvcrtseeklockingfilenoLK_LOCK	ExceptioncloseRuntimeErrorfcntlflockLOCK_EX)r>   rK   excrS   s       r   	__enter__z_FileLock.__enter__a   s_   	td;;;	5))7d??Ta   tx00&.!DDDD T T T   "#IJJPSST
TDHOO--u}==== T T T   "#IJJPSST s1   AB 
C)0CC"6D 
E#0EEc                   | j         d S t          j        dk    rc	 dd l}| j                             d           |                    | j                                         |j        d           nX# t          $ r Y nLw xY w	 dd l	}|
                    | j                                         |j                   n# t          $ r Y nw xY w	 | j                                          d | _         d S # d | _         w xY w)NrD   r   rE   )r=   rI   rJ   rK   rL   rM   rN   LK_UNLCKrP   rS   rT   LOCK_UNrQ   )r>   exc_typerV   tbrK   rS   s         r   __exit__z_FileLock.__exit__y   s   8F7d??a   tx00&/1EEEE   DHOO--u}====   	HNNDHHHtDHOOOOs0   AA- -
A:9A:>6B5 5
CCC( (	C1N)r:   r   )__name__
__module____qualname__r?   rW   r]   r-   r(   r   r9   r9   \   sF             0    r(   r9   r:   list[dict[str, Any]]c                   	 t          | dd          5 }t          j        |          }d d d            n# 1 swxY w Y   n:# t          $ r g cY S t          $ r  t
                              d|            g cY S w xY wt          |t                    r|	                    d          n|}t          |t                    sg S d |D             S )Nrutf-8encodingz.Ignoring corrupt active session registry at %sentriesc                <    g | ]}t          |t                    |S r-   )r   r"   .0entrys     r   
<listcomp>z!_read_entries.<locals>.<listcomp>   s'    BBBe*UD*A*ABEBBBr(   )rH   jsonloadFileNotFoundErrorrP   r   r   r   r"   r#   list)r:   fhdatarg   s       r   _read_entriesrs      s"   $g... 	!"9R==D	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	!   			   GNNN			 &0d%;%;Edhhy!!!Ggt$$ 	BBwBBBBs2   A 5A 9A 9A A8&A87A8rg   Nonec                   | j                             dd           |                     | j         dt	          j                     dt          j                    j         d          }t          |dd          5 }t          j        d|i|d	           d d d            n# 1 swxY w Y   t	          j        ||            d S )
NTrA   .z.tmpwrd   re   rg   )	sort_keys)rF   rG   	with_namerJ   rI   getpiduuiduuid4hexrH   rm   dumpreplace)r:   rg   tmprq   s       r   _write_entriesr      s    KdT222
..DILL	LLdjll6FLLL
M
MC	c3	)	)	) <R	9g&d;;;;< < < < < < < < < < < < < < <JsDs   9BB#&B#pidOptional[float]c                    	 dd l }t          |                    |                                                     S # t          $ r Y d S w xY w)Nr   )psutilr   Processcreate_timerP   )r   r   s     r   _process_start_timer      sX    V^^C((4466777   tts   7: 
AAc                f    | | dk    rd S 	 t          |           S # t          t          f$ r Y d S w xY w)N )r   r   r   )r   s    r   _optional_floatr      sL    }tU||z"   tts    00process_start_timer   c                F   	 t          |           }n# t          t          f$ r Y dS w xY w|dk    rdS 	 ddlm} t           ||                    }n# t          $ r Y dS w xY w|sdS t          |          }|dS t          |          }|dS t          ||z
            dk     S )NFr   )_pid_existsTgMbP?)
r   r   r   gateway.statusr   r   rP   r   r   abs)r   r   pid_intr   existsexpected_startcurrent_starts          r   
_pid_aliver      s    c((z"   uu!||u......kk'**++   uu u$%788Nt'00Mt}~-..66s    ''A 
A A c                    d | D             S )Nc                ~    g | ]:}t          |                    d           |                    d                    8|;S )r   r   )r   r#   ri   s     r   rl   z_prune_dead.<locals>.<listcomp>   sQ       eii&&		2F(G(GHH  r(   r-   )rg   s    r   _prune_deadr      s#        r(   c                  R    e Zd ZU ded<   ded<   ded<   dZded<   dZded	<   ddZdS )ActiveSessionLeaser   lease_id
session_idsurfaceTr   enabledFreleasedr   rt   c                D    | j         s| j        sd S t          |            d S r<   )r   r   release_active_session)r>   s    r   releasezActiveSessionLease.release   s.    = 	 	Ft$$$$$r(   N)r   rt   )r^   r_   r`   __annotations__r   r   r   r-   r(   r   r   r      sg         MMMOOOLLLGH% % % % % %r(   r   )metadatar   r   r   Optional[dict[str, Any]]2tuple[Optional[ActiveSessionLease], Optional[str]]c                ,   t          |          }t          j                    j        }|t	          || |d          dfS t          j                    }|t          |           t          |          t          j                    t          t          j                              ||d}|r!d |
                                D             |d<   t                      }t          t                                5  t          |          }	t          |	          }
t!          |	          t!          |
          z
  }|rt"                              d|           t!          |
          }||k    rKt'          ||
           t"                              d|||           dt)          ||          fcddd           S |
                    |           t'          ||
           ddd           n# 1 swxY w Y   t	          |t          |           t          |          	          dfS )
zAcquire an active-session slot.

    Returns ``(lease, None)`` on success.  When the cap is disabled, the lease is
    a no-op object so callers can unconditionally call ``release()``.
    NF)r   r   r   r   )r   r   r   r   r   
started_at
updated_atc                ^    i | ]*\  }}t          |t                    t          |          |+S r-   )r   r   )rj   kvs      r   
<dictcomp>z.try_acquire_active_session.<locals>.<dictcomp>  sC     
 
 
!QjC6H6H
FFA
 
 
r(   r   z'Pruned %d stale active session lease(s)z9Active session limit reached: active=%d max=%d surface=%s)r   r   r   )r'   r{   r|   r}   r   timer   rI   rz   r   itemsr4   r9   r7   rs   r   lenr   infor   r.   append)r   r   r   r   r*   r   nowrk   
state_pathraw_entriesrg   prunedr)   s                r   try_acquire_active_sessionr      sz    36::Lz||H!!	
 
 

  	 )++C*oow<<y{{1")++>> E  

 
"*.."2"2
 
 
j J	:<<	 	  , ,#J//k**[!!CLL0 	KKKA6JJJ7||<'':w///KKK	   5lLQQQ, , , , , , , ,  	uz7+++#, , , , , , , , , , , , , , ,& z??G   	 s   1B.G,%GG!$G!leasec                f    t                      }	 t          t                                5  t          t	          |                    } fd|D             }t          |          t          |          k    rt          ||           d d d            n# 1 swxY w Y   d _        d S # d _        w xY w)Nc                n    g | ]1}t          |                    d           pd          j        k    /|2S )r   r   )r   r#   r   )rj   rk   r   s     r   rl   z*release_active_session.<locals>.<listcomp>/  sI       uyy,,233u~EE EEEr(   T)r4   r9   r7   r   rs   r   r   r   )r   r   rg   kepts   `   r   r   r   *  s    Jz||$$ 	1 	1!-
";";<<G   $  D
 4yyCLL((z4000	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 s/   B' ABB' BB' BB' '	B0c                     t                      } t          t                                5  t          t	          |                     }t          | |           |cddd           S # 1 swxY w Y   dS )z@Return the pruned active-session registry for diagnostics/tests.N)r4   r9   r7   r   rs   r   )r   rg   s     r    active_session_registry_snapshotr   :  s    J	:<<	 	   mJ7788z7+++                 s   .A%%A),A))r
   )r   r   r   r   r   r   )r   r   r   r   )r)   r   r*   r   r   r   )r   r   )r:   r   r   ra   )r:   r   rg   ra   r   rt   )r   r   r   r   )r   r   r   r   r<   )r   r   r   r   r   r   )rg   ra   r   ra   )
r   r   r   r   r   r   r   r   r   r   )r   r   r   rt   )r   ra   )%__doc__
__future__r   rm   loggingrI   r   r{   dataclassesr   pathlibr   typingr   r   hermes_constantsr	   	getLoggerr^   r   r   r'   r.   r1   r4   r7   r9   rs   r   r   r   r   r   r   r   r   r   r-   r(   r   <module>r      sb    # " " " " "   				   ! ! ! ! ! !                       , , , , , ,		8	$	$    @8 8 8 8"   ) ) ) )1 1 1 11 1 1 12 2 2 2 2 2 2 2jC C C C         7 7 7 7 70    
% 
% 
% 
% 
% 
% 
% 
%$ *.= = = = = =@         r(   