
    yj                        d dl mZ d dlmZ d dlmZ d dlmZ d dlm	Z	 d dl
mZ d dlmZmZmZmZmZmZmZmZmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZ d dl m!Z!m"Z" d dl#m$Z$m%Z% d dl&m'Z'm(Z(m)Z)m*Z* d dl+m,Z, d dl-m.Z.m/Z/m0Z0 d dl1m2Z2 d dl3m4Z4 d dl5m6Z6 ddl7m8Z8m9Z9 ddl:m;Z;  ee<          Z=e G d d                      Z>dZ? e(             dZ@deAdeAdeAfdZB e'e?e,jC        jD         d  e(            e	!           e'jE        e?e,jC        jF         d e@"          d#edeAdeAdeGeAef         d$z  fd%                        ZHd&eGeAe%jI        f         deJfd'ZK	 dJdeAd(eGeAef         d$z  deeLe$jM                          fd)ZNd*d+d#ed,e%jO        deAd-ePde4e$jM                 f
d.ZQd*d/d#edeAdeAd0ePde$jM        f
d1ZRd#ed,e%jS        deAdeAde$jM        f
d2ZT	 dKd#ed4ed5eUe         d6eJdeJf
d7ZVd#edeAdeAde>fd8ZW	 dJd#edeAd9eAd:eAd$z  de$jM        f
d;ZXd#edeAdeAd<eYeA         dePf
d=ZZdeAdeAdeeLe$j[                          fd>Z\deAdeAdeeLeAeGeAef         eGeAef         ePf                  fd?Z]d#edeAdeAd<eGeAe%jI        f         deUe$j^                 f
d@Z_dAdBd#edeAdeAd<eGeAe%jI        f         dCePdeUe$j^                 fdDZ`d#edeAdeAdEeAde%jI        f
dFZad#edeAdeAdGeAdHe%jI        dd$fdIZbd$S )L    )	dataclass)	getLogger)Any)cast)NOT_NONE)generate)	Selectand_caser   deletefuncinsertselectupdate)r   )CursorResult)IntegrityError)AsyncSession)make_transient_to_detached)
BigIntegerBoolean)modelsschemas)cacheget_cache_namespacesafe_cache_deletesafe_cache_set)settings)ConflictExceptionObserverExceptionResourceNotFoundException)apply_filter)GetOrCreateResult)get_external_vector_store   )get_or_create_peersget_peer)get_or_create_workspacec                   (    e Zd ZU dZeed<   eed<   dS )SessionDeletionResultz6Result of a session deletion including cascade counts.messages_deletedconclusions_deletedN)__name__
__module____qualname____doc__int__annotations__     8/DATA/AppData/hermes/projects/honcho/src/crud/session.pyr)   r)   '   s0         @@r3   r)   z4v2:workspace:{workspace_name}:session:{session_name}z:lock:v2workspace_namesession_namereturnc                 ^    t                      dz   t                              | |          z   S )zGenerate cache key for session.:r5   r6   )r   SESSION_CACHE_KEY_TEMPLATEformatr:   s     r4   session_cache_keyr=   3   s=     	
	
$
+
+)% , 
 
	
r3   s)keyttlprefix	condition)r?   r@   rA   dbNc           	      p  K   |                      t          t          j                                      t          j        j        |k                                  t          j        j        |k                         d{V }|dS |j        |j        |j        |j        |j	        |j
        |j        |j        dS )zNFetch a session from the database and return as a plain dict for safe caching.Nidnamer5   	is_active
h_metadatainternal_metadataconfiguration
created_at)scalarr   r   Sessionwherer5   rG   rF   rH   rI   rJ   rK   rL   )rC   r5   r6   objs       r4   _fetch_sessionrQ   ?   s      " 		v~	v~,>	?	?	v~"l2	3	3       C
 {tf,]n 2*n	 	 	r3   peer_configsc                 X    t          d |                                 D                       S )z
    Count the number of peers that will be observing others based on their configurations.

    Args:
        peer_configs: Dictionary of peer names to their session configurations

    Returns:
        Number of peers that will be observing others
    c              3   (   K   | ]}|j         	d V  dS )r$   N)observe_others).0configs     r4   	<genexpr>z,count_observers_in_config.<locals>.<genexpr>o   s*      NNV8MNqNNNNNNr3   )sumvalues)rR   s    r4   count_observers_in_configr[   c   s-     NN|2244NNNNNNr3   filtersc                 N  K   t          t          j                                      t          j        j        | k                                  t          j        j        dk              }t          |t          j        |          }|                    t          j        j                  S )z1
    Get all active sessions in a workspace.
    T)	r   r   rN   rO   r5   rH   r!   order_byrL   )r5   r\   stmts      r4   get_sessionsr`   r   st       	v~	v~,>	?	?	v~'4/	0	0 	 fng66D==2333r3   F_retrysessionrb   c                  K   |j         st          d          t          | ||j                    d{V }d}|^t          j        di |}t          |           |                     |d           d{V }|j        st          d|j          d|           d}d}d}	d}
|k|j	        r9t          |j	                  }|t          j        k    rt          |j         |          t          | t          j        |                     d{V }	t          j        ||j         |j        pi |j        r|j                            d	          ni 
          }	 |                                 4 d{V  |                     |           ddd          d{V  n# 1 d{V swxY w Y   d}d}n# t,          $ rV t.                              d|j                    |rt3          d|j                    dt5          | ||d           d{V cY S w xY w|j        |j        |j        k    r|j        |_        d}|j        P|j        pi                                 }|j                            d	          }i ||}|j        |k    r	||_        d}|j	        rKt;          | |d |j	        D                        d{V }
t=          | ||j         |j	        d           d{V  |                                  d{V  |	|	                                  d{V  |
|
                                  d{V  |rtC          ||j                   }tE          ||j#        |j         |j$        |j        |j        |j%        |j        |j&        dt          j'        j(                   d{V  t.                              d|j         |           tS          ||          S )a]  
    Get an active session in a workspace or create it if it does not exist.

    If the session already exists, provided metadata replaces the current
    metadata, provided configuration keys are merged into the existing
    configuration, and any provided peers are ensured to be members of the
    session. If the session does not exist, the workspace and peers are created
    as needed before the session is created.

    Args:
        db: Database session
        session: Session creation payload, including optional metadata,
            configuration, and session-peer configuration
        workspace_name: Name of the workspace
        _retry: Whether to retry after a concurrent create conflict

    Returns:
        GetOrCreateResult containing the session and whether it was created

    Raises:
        ValueError: If session.name is empty
        ResourceNotFoundException: If the named session exists but is inactive
        ObserverException: If adding peers would exceed the observer limit
        ConflictException: If concurrent creation prevents fetching or creating
            the session
    zSession name must be providedNFloadSession  not found in workspace rG   Texclude_noner5   rG   rI   rK   z5Race condition detected for session: %s, retrying getz!Unable to create or get session: ra   c                 8    g | ]}t          j        |           S ri   r   
PeerCreaterV   	peer_names     r4   
<listcomp>z)get_or_create_session.<locals>.<listcomp>   s3       7@"	222  r3   r5   peers)r5   r6   
peer_namesfetch_after_upsertrE   )expirez(Session %s cache updated in workspace %s)createdr2   )*rG   
ValueErrorrQ   r   rN   r   mergerH   r    rv   r[   r   SESSION_OBSERVERS_LIMITr   r'   r   WorkspaceCreatemetadatarK   
model_dumpbegin_nestedaddr   loggerdebugr   get_or_create_sessionrI   copyr%   _get_or_add_peers_to_sessioncommitpost_commitr=   r   rF   r5   rJ   rL   CACHEDEFAULT_TTL_SECONDSr"   )rC   rc   r5   rb   session_datahoncho_sessionrP   needs_cache_updatery   	ws_resultpeers_resultobserver_countexisting_configincoming_configmerged_config	cache_keys                   r4   r   r      s     D < :8999'NGLIIIIIIIIL -1Nn,,|,,"3'''!xx%x88888888 ' 	+Q7<QQQQ  
 GIL  	F6w7IJJN @@@'nEEE 2#888
 
 
 
 
 
 
 
	  )'-2$'/:::MMM
 
 
	Y(( ' ' ' ' ' ' ' '~&&&' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '!%GG 	Y 	Y 	YLLG    'FFF  /r7NSWXXXXXXXXXXXX	Y ()W-===(/(8N%!% ,-;ArGGIIO%3>>D>QQOBB/BM+}<</<,%)"  
0) DKDV  
 
 
 
 
 
 
 
 
 +) )$
 
 
 	
 	
 	
 	
 	
 	
 	
 ))++ ##%%%%%%%%%&&(((((((((  
%nglCC	$'&+"0"?+5,7%3%E!/!=,7	 	 >5
 
 
 	
 	
 	
 	
 	
 	
 	
 	6n	
 	
 	
 ^W====s7   F* ,FF* 
FF* !F"F* *AH
	H
include_inactiver   c                  K   t          | ||           d{V }|t          d| d|           |s|d         st          d| d|           t          j        di |}t	          |           |                     |d           d{V }|S )a  
    Get a session in a workspace.

    Args:
        db: Database session
        session_name: Name of the session
        workspace_name: Name of the workspace
        include_inactive: If True, return sessions even if they are marked for deletion.
            This should only be used for internal operations like the deletion task.

    Returns:
        The session

    Raises:
        ResourceNotFoundException: If the session does not exist or is inactive
    Nrg   rh   rH   Fre   r2   )rQ   r    r   rN   r   r{   )rC   r6   r5   r   datarP   rc   s          r4   get_sessionr   &  s      .  NLAAAAAAAAD|'M|MM^MM
 
 	
  
D$5 
'M|MM^MM
 
 	

 .
 
 4
 
 Cs###HHSuH--------GNr3   c                 V  K   t          | t          j        |          |           d{V j        }d}|j        |j        |j        k    r|j        |_        d}|j        N|j        pi                                 }i ||j                            d          }|j        |k    r	||_        d}|st          
                    d||           |S |                                  d{V  t          ||          }t          |           d{V  t          
                    d|           |S )	a  
    Get or create a session, then apply metadata and configuration updates.

    Provided metadata replaces the current metadata when present. Provided
    configuration keys are merged into the existing configuration instead of
    replacing it wholesale.

    Args:
        db: Database session
        session: Session update schema
        workspace_name: Name of the workspace
        session_name: Name of the session

    Returns:
        The updated session

    Raises:
        ResourceNotFoundException: If the named session exists but is inactive
        ConflictException: If concurrent creation prevents fetching or creating
            the session
    ri   )r5   NFTrj   z5Session %s unchanged in workspace %s, skipping updatezSession %s updated successfully)r   r   SessionCreateresourcer~   rI   rK   r   r   r   r   r   r=   r   )	rC   rc   r5   r6   r   needs_updatebase_configr   r   s	            r4   update_sessionr   S  s     8 $%<888
 
 
 	
 	
 	
 	
 	
 	
 	  L#(AWEU(U(U$+$4!(%39r??AA

#..D.AA
 '=88+8N(L C	
 	
 	

 
))++ ".,??I
I
&
&&&&&&&&
LL2LAAAr3     modelfilter_conditions
batch_sizec                   K   d}|j         j        j                                        d         }	 t	          |                              t          |                               |          }t          |                              |	                    |                    }t          t          t                   |                     |           d{V           }|j        pd}	||	z  }|	dk    rn|S )aI  
    Delete records in batches that match the given filter conditions.

    Args:
        db: Database session
        model: SQLAlchemy model class
        filter_conditions: List of SQLAlchemy filter conditions
        batch_size: Number of records to delete per batch

    Returns:
        Total number of records deleted
    r   TN)	__table__primary_keycolumnsrZ   r   rO   r
   limitr   in_typing_castr   r   executerowcount)
rC   r   r   r   total_deletedprimary_key_columnsubquerydelete_stmtdelete_resultbatch_deleteds
             r4   _batch_delete_matchingr     s      $ M4<CCEEaH
%&&,,T3D-EFFLLZXX 	 Umm))*<*@*@*J*JKK#L$5RZZ=T=T7T7T7T7T7T7TUU%.3!&A
 r3   c                 l  K   t          | ||d           d{V }	 |                     t          t          j                                      t          t          j        t          j        j	        dd          |k    t          j        t          j        j	        dd          |k                                   d{V  |                     t          t          j
                                      t          j
        j        |j        k                         d{V  |                     t          t          j                                      t          j        j        |k    t          j        j        |k                         d{V }t#          |                                                                          }t)                      }|4|r1i }|D ]0}|                    |j        g                               |           1g }	|                                D ]M}
|
                    d            t5          |
          D ]$\  }}|	                    |j         d	|            %N	 |                    d
|          }|                    ||	           d{V  t:                              dt?          |	           d|            n7# t@          $ r*}t:          !                    d| d|            Y d}~nd}~ww xY wtE          | t          j        t          j        j        |k    t          j        j        |k    gd           d{V  |                     t          t          j#        j        t          j#        j$        t          j#        j%                                      t          j#        j        |k    t          j#        j        |k                         d{V }|                                }||ri }|D ]R}|                    d||j$        |j%                  }|                    |g                               |j                   S|&                                D ]\  }}	 |                    ||           d{V  t:                              dt?          |           d|            P# t@          $ r*}t:          !                    d| d|            Y d}~d}~ww xY wtE          | t          j#        t          j#        j        |k    t          j#        j        |k    gd           d{V }tE          | t          j'        t          j'        j        |k    t          j'        j        |k    gd           d{V }|                     t          t          j(                                      t          j(        j        |k    t          j(        j        |k                         d{V  |                     |           d{V  | )                                 d{V  tU          tW          ||                     d{V  t:                              d|           nJ# t@          $ r=}t:          ,                    d||           | -                                 d{V  |d}~ww xY wt]          ||          S )at  
    Delete a session and all associated data (hard delete).

    This performs cascading deletes for all session-related data including:
    - Active queue sessions
    - Queue items
    - Message embeddings (batched)
    - Documents (theory-of-mind data, batched)
    - Messages (batched)
    - Session peer associations
    - The session itself

    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session

    Returns:
        SessionDeletionResult containing cascade counts

    Raises:
        ResourceNotFoundException: If the session does not exist
    Tr   Nr9         c                     | j         S N)rF   )es    r4   <lambda>z delete_session.<locals>.<lambda>  s    !$ r3   )r?   _messagezDeleted z message vectors for session z-Failed to delete message vectors for session z: r   )r   documentz document vectors from z'Failed to delete document vectors from z*Session %s and all associated data deletedzFailed to delete session %s: %s)r*   r+   )/r   r   r   r   ActiveQueueSessionrO   r
   r   
split_partwork_unit_key	QueueItem
session_idrF   r   MessageEmbeddingr6   r5   listscalarsallr#   
setdefault
message_idappendrZ   sort	enumerateget_vector_namespacedelete_manyr   r   len	Exceptionwarningr   DocumentobserverobserveditemsMessageSessionPeerr   r   r=   errorrollbackr)   )rC   r5   r6   r   embedding_result
embeddingsexternal_vector_storemessage_chunksemb
vector_idschunks	chunk_idxchunk	namespacer   
doc_result	documentsdocs_by_namespacedocdoc_idsr+   r*   s                         r4   delete_sessionr     s/     4 '
L.4        NY jj6,--33OF$=$KSRSTT%&OF$=$KSRSTT#$  	
 	
 		
 		
 		
 		
 		
 		
 		
 jj6#$$** +~/@@ 
 
 	
 	
 	
 	
 	
 	
 	
 "$6*++11'4D'6.H "
 "
 
 
 
 
 
 
 *224488::;;
 9 ; ; !,,GIN! J J))#."==DDSIIII %'J(//11 I I///(1&(9(9 I I$Iu%%)9&G&GI&G&GHHHHI1FF~ 	 ,77	:NNNNNNNNN[s:[[\[[       WLWWTUWW        %#'4D'6.H 
 
 
 	
 	
 	
 	
 	
 	
 	
 ::"((  e,<..@ 	
 	
 	
 	
 	
 	
 	
 	

 NN$$	 !,,68  K K1FF"LL	 	 ",,Y;;BB36JJJJ '8&=&=&?&? 
 
"	7	/;;IwOOOOOOOOOLLS3w<<SS	SS    !   NNR)RRqRR        %;O,<..@ %
 %
 %
 
 
 
 
 
 
 "8N+|;-? "
 "
 "
 
 
 
 
 
 
 jj6%&&,,"/<?"1^C 
 
 	
 	
 	
 	
 	
 	
 	
 ii'''''''''iikk   1., O OPPPPPPPPPA<PPPP   6aHHHkkmm
 !)/   sp   I
Y (AK Y 
K< K72Y 7K<<E'Y $A	R.-Y .
S"8 SY S""E8Y 
Z"%8ZZ"original_session_namecutoff_message_idc                   K   t          t          j                                      t          j        j        k                                  t          j        j        |k                                  t          j        j        dk              }|                     |           d{V }|                                }|t          d          d}|t          t          j
                                      t          j
        j        |k    t          j
        j        |k              }|                     |           d{V }|st          d          t          j        t                      |j        |j                  |                                |                                  d{V  t          t          j
                                      t          j
        j        |k              }|B|@|                    t          j
        j        t+          |j        t,                    k              }|                    t          j
        j                  }|                     |           d{V }|                                }	|	sS fd|	D             }
t5          t          j
                                      t          j
                  }|                     ||
           d{V }t          t          j                                      t          j        j        |k              }|                     |           d{V }|                                                                }|D ]>}t          j        j        |j        |j                  }|                     |           ?|                                  d{V  t>                               d|           S )	a  
    Clone a session and its data. If cutoff_message_id is provided,
    only clone messages up to and including that message.

    The following data is copied to the new session:
    - Session metadata
    - Session configuration
    - All messages (or up to cutoff_message_id) with their content, metadata, and peer associations
    - Session-peer associations with their configurations (observe_me, observe_others)

    The new session gets a unique ID (nanoid) and fresh timestamps.

    Args:
        db: SQLAlchemy session
        workspace_name: Name of the workspace the target session is in
        original_session_name: Name of the session to clone
        cutoff_message_id: Optional ID of the last message to include in the clone

    Returns:
        The newly created session
    TNzOriginal session not foundz<Message not found or doesn't belong to the specified sessionrl   c           	      T    g | ]$}j         |j        |j        |j        |j        d %S ))r6   contentrI   r5   rr   seq_in_session)rG   r   rI   rr   r   )rV   r   new_sessionr5   s     r4   rs   z!clone_session.<locals>.<listcomp>  sR     
 
 
  (,!,, *%4	
 	

 
 
r3   r6   rr   r5   rK   zSession %s cloned successfully)!r   r   rN   rO   r5   rG   rH   r   scalar_one_or_noner    r   	public_idr6   rM   rz   generate_nanoidrI   rK   r   flushrF   r   r   r^   r   r   r   	returningr   rr   r   r   r   )rC   r5   r   r   r_   resultoriginal_sessioncutoff_messagemessages_to_clone_scalarsmessages_to_clonenew_messagesinsert_stmtsession_peerssession_peernew_session_peerr   s    `             @r4   clone_sessionr   }  s     : 	v~	v~,>	?	?	v~"&;;	<	<	v~'4/	0	0	 	 ::d########F0022'(DEEE N$fn%%++N$(99N'+@@
 
  "yy...... 	N  
 .%#.&4	  K FF;
((** &.!!''#'<< D $)Czz&.+tN4Ez/R/RRSS==*++D ')jj&6&6 6 6 6 6 6 615577 
 
 
 
 
 )
 
 
L ((226>BBK::k<88888888F &$%%++'+@@ D ::d########FNN$$((**M% ! !!-$)",)&4	
 
 
 	    
))++
LL13HIII r3   rv   c                   K   t          | ||           d{V  t          t          j                                      t          j        j        |k    t          j        j        |k    t          j        j                            |          t          j        j	        
                    d                                        t          j                              }|                     |           d{V  |                                  d{V  dS )a}  
    Remove specified peers from a session.

    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session
        peer_names: Set of peer names to remove from the session

    Returns:
        True if peers were removed successfully

    Raises:
        ResourceNotFoundException: If the session does not exist
    Nleft_atT)r   r   r   r   rO   r6   r5   rr   r   r  is_rZ   r   nowr   r   )rC   r5   r6   rv   update_stmts        r4   remove_peers_from_sessionr    s      , b,
7
77777777 	v!""	+|;-?(,,Z88&**400	

 

 


	#	#  **[
!
!!!!!!!!
))++4r3   c                   K   t          t          j                                      t          j        t          t          j        j        t          j        j        k    t          j        j        t          j        j        k                        	                    t          j        j
        |k              	                    t          j        j        | k              	                    t          j        j                            d                    S )z
    Get all peers from a session.

    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session

    Returns:
        Paginated list of Peer objects in the session
    N)r   r   Peerjoinr   r
   rG   rr   r5   rO   r6   r  r  r:   s     r4   get_peers_from_sessionr    s      " 	v{	 F$6$@@*f.@.OO 

 

 
v!.,>	?	?	v{)^;	<	<	v!)--d33	4	4r3   c                 (  K   t          t          j        j                            d          t          j        j                            d          t          j        j                            d          t          j        j                            d                              d                    	                    t          j        t          t          j        j        t          j        j        k    t          j        j        t          j        j        k                                            t          j        j        |k                                  t          j        j        | k                                  t          j        j        | k              }|S )a  
    Get configuration from both SessionPeer and Peer tables for all peers in a session.
    NOTE: does not filter for active peers. Will return peers that have left the session.

    Args:
        workspace_name: Name of the workspace
        session_name: Name of the session

    Returns:
        Select statement returning peer_name, peer_configuration, session_peer_configuration,
        and a boolean indicating if the peer is currently in the session
    rr   peer_configurationsession_peer_configurationNrH   )r   r   r	  rG   labelrK   r   r  r  r
  r
   rr   r5   rO   r6   )r5   r6   r_   s      r4   get_session_peer_configurationr  8  s     " 	K"";//K%++,@AA,223OPP'++D1188EE		
 	
 
 F$6$@@*f.@.OO 

 

 
v!.,>	?	?	v{)^;	<	<	v!0NB	C	C! 	& Kr3   c                   K   t          |          }|t          j        k    rt          ||          t	          t
          j                                      t
          j        j        |k                                  t
          j        j	        |k              }| 
                    |           d{V }|                                }|t          d| d|           t          t
          j                                      t
          j        j        |k    t
          j        j        |k    t
          j        j                            d                                        t'          j                              }| 
                    |           d{V }t+          | |d |D                        d{V }	t-          | |||           d{V }
|                                  d{V  |	                                 d{V  |
S )a  
    Set peers for a session, overwriting any existing peers.
    If peers don't exist, they will be created.

    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session
        peer_names: Set of peer names to set for the session

    Returns:
        List of SessionPeer objects for all peers in the session

    Raises:
        ResourceNotFoundException: If the session does not exist
    Nrg   rh   r  c                 8    g | ]}t          j        |           S rn   ro   rq   s     r4   rs   z)set_peers_for_session.<locals>.<listcomp>  s&    NNNiw!y111NNNr3   rt   )r5   r6   rv   )r[   r   r|   r   r   r   rN   rO   r5   rG   r   r   r    r   r   r6   r  r  rZ   r   r  r%   r   r   r   )rC   r5   r6   rv   r   r_   r   rc   r  r   ru   s              r4   set_peers_for_sessionr  ^  s>     . /z::N888n=== 	v~	v~,>	?	?	v~"l2	3	3 	
 ::d########F''))G'M|MM^MM
 
 	
 	v!""	+|;-?&**400

 


 


	#	#  ::k********F -
%NN:NNN        L /
%!	        E ))++

"
"
$
$$$$$$$$Lr3   T)rw   rw   c          
        K   |s|sg S t          t          j                                      t          j        j        k    t          j        j        k    t          j        j                            d                    }|                     |           d{V }t          |
                                                                          S t          |          }|dk    r;t          t          j                                                  t          j        j        k    t          j        j        k    t          j        j                            d          t          j        j                            |                                          t          j        j        d         j                            t*                              }|                     |           d{V }|                                pd}	|	|z   }
|
t.          j        k    rt3          |
          t5          t          j                                      fd|                                D                       }|                    g dt          j                    dt?          t          j        j                             d          |j!        j        ft          j        j                  d          }|                     |           d{V  |sg S t          t          j                                      t          j        j        k    t          j        j        k    t          j        j                            d                    }|                     |           d{V }t          |
                                                                          S )	aU  
    Upsert session-peer memberships for a session and optionally fetch the
    active memberships afterward.

    New peers are inserted, peers that previously left the session are rejoined,
    and already-active peers keep their existing session-level configuration.

    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session
        peer_names: Mapping of peer names to session-level configuration
        fetch_after_upsert: If True, query and return the active session peers
            after the upsert. If False, skip that read and return an empty list.

    Returns:
        Active SessionPeer objects after the upsert, or an empty list when the
        post-upsert fetch is skipped

    Raises:
        ObserverException: If adding peers would exceed the observer limit
    Nr   rU   c           	      n    g | ]1\  }}|t          j                    d |                                d2S )N)r6   rr   r5   	joined_atr  rK   )r   r  r   )rV   rr   rK   r6   r5   s      r4   rs   z0_get_or_add_peers_to_session.<locals>.<listcomp>  sZ     
	
 
	
 
	
 )	= !-&"0!XZZ!.!9!9!;!; 
	
 
	
 
	
r3   )r6   rr   r5   )else_)r  r  rK   )index_elementsset_)"r   r   r   rO   r6   r5   r  r  r   r   r   r   r[   r   countrr   notin_keysrK   astextr   r   rM   r   r|   r   	pg_insertrZ   r   on_conflict_do_updater  r   is_notexcluded)rC   r5   r6   rv   rw   select_stmtr   new_observer_countexisting_observers_stmtexisting_observer_counttotal_observersr_   s    ``         r4   r   r     s     >  	,! 	IV/0066+|;-?&**400
 

 zz+........FNN$$((**+++ 3:>>A #)"6"6"<"<+|;-?&**400(//!!  ,-=>EJJ 
#
 
#
 zz"9::::::::"(--//"6Q14FFX===#L/BBB V'((//
	
 
	
 
	
 
	
 
	
 -7,<,<,>,>
	
 
	
 
	
 D" %%FFF!#+22488$-:UV(6  
 
 & 
 
D **T

 	 +,,22'<7)^;"&&t,, K
 ::k********F  $$&&'''r3   peer_idc                   K   t          t          j                                      t          j        j        |k    t          j        j        |k    t          j        j        |k              }|                     |           d{V }|                                }|t          d| d| d|           t          j        di |j        S )ac  
    Get the configuration for a peer in a session.


    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session
        peer_id: Name of the peer


    Returns:
        Configuration for the peer

    Raises:
        ResourceNotFoundException: If the session or peer does not exist
    NzSession peer z not found in session z in workspace r2   )r   r   r   rO   r5   r6   rr   r   r   r    r   SessionPeerConfigrK   )rC   r5   r6   r'  r_   r   r   s          r4   get_peer_configr*    s      0 &$%%++)^;'<7$/ D
 ::d########F,,..L'gGgg<ggWegg
 
 	
 $BB|'ABBBr3   rr   rW   c           	        K   t          | ||           d{V  t          | |t          j        |                     d{V  t	          t
          j                                      t
          j        j        |k                                  t
          j        j	        |k                                  t
          j        j
        |k              }|                     |           d{V }|                                }|j        rC|r"|j        r|j                            dd          nd}|st	          t!          j                                                  t
          j        j        |k    t
          j        j
        |k    t
          j        j                            d          t
          j        j	        |k    t
          j        j        d         j                            t,                              }	|                     |	           d{V }|                                pd}
|
dz  }
|
t0          j        k    rt5          ||
          |                    d          }|rE|j        r6|j                                        }|                    |           ||_        n5||_        n-t          j        ||||	          }|                     |           |                                  d{V  dS )
ai  
    Set the configuration for a specific peer in a session.

    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session
        peer_name: Name of the peer
        config: The peer configuration to set

    Raises:
        ObserverException: If the update would exceed the observer limit
    Nri   rU   Fr   r$   Trj   r   ) r   r&   r   rp   r   r   r   rO   r6   rr   r5   r   r   rU   rK   getr   r  r  r  r  r   r   rM   r   r|   r   r   r   r   r   r   )rC   r5   r6   rr   rW   r_   r   r   is_currently_observerr$  r   update_data
new_configs                r4   set_peer_configr0  >  s     * b,
7
77777777
2~w'9y'I'I'I
J
JJJJJJJJ 	v!""	v!.,>	?	?	v!+y8	9	9	v!0NB	C	C	 	 ::d########F,,..L  F  , :L&**+;UCCC 	 % 	F&,TZ\\&:&:&@&@"/<?"1^C"*..t44","01ABINN 	' 	'# ::&=>>>>>>>>F#]]__1N aN @@@'nEEE###66K % 	5%388::Jk***)3L&&)4L&& )%)%	
 
 
 	|
))++r3   r   )r   )cdataclassesr   loggingr   typingr   r   r   cashewsr   nanoidr   r   
sqlalchemyr	   r
   r   r   r   r   r   r   sqlalchemy.dialects.postgresqlr  sqlalchemy.enginer   sqlalchemy.excr   sqlalchemy.ext.asyncior   sqlalchemy.ormr   sqlalchemy.typesr   r   srcr   r   src.cache.clientr   r   r   r   
src.configr   src.exceptionsr   r   r    src.utils.filterr!   src.utils.typesr"   src.vector_storer#   peerr%   r&   	workspacer'   r,   r   r)   r;   SESSION_LOCK_PREFIXstrr=   r   r   lockedDEFAULT_LOCK_TTL_SECONDSdictrQ   r)  r0   r[   tuplerN   r`   r   boolr   r   SessionUpdater   r   r   r   r   setr  r	  r  r  r   r  r   r*  r0  r2   r3   r4   <module>rO     sS   ! ! ! ! ! !             & & & & & &       . . . . . . U U U U U U U U U U U U U U U U U U U U U U > > > > > > * * * * * * ) ) ) ) ) ) / / / / / / 5 5 5 5 5 5 0 0 0 0 0 0 0 0                                   
 * ) ) ) ) ) - - - - - - 6 6 6 6 6 6 / / / / / / / / . . . . . .	8		         T ,,..888 	c 	 	 	 	 	 	 ">-000  	   ">2555  
  
#s(^d	    2OsG556OO O O O" &*4 44#s(^d"4 E&.!"4 4 4 4. _> _> _>_>"_> _>
 _> v~&_> _> _> _>N #* * *** *
 * ^* * * *ZBB"B B 	B
 ^B B B BR 	! !!! Cy! 	!
 	! ! ! !H~~&)~9<~~ ~ ~ ~J %)	p ppp p Tz	p
 ^p p p pf&&& & C	&
 
& & & &R E&+   >### E#tCH~tCH~t;<=# # # #LFFF F S'334	F
 
&
F F F F^  $l( l( l(l(l( l( S'334	l( l( 
&
l( l( l( l(^%C%C%C %C 	%C
 %C %C %C %CPVVV V 	V
 %V 
V V V V V Vr3   