
    yj                     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mZmZmZmZmZmZmZ d dlmZ d dl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# d dl$m%Z%m&Z& d dl'm(Z( d dl)m*Z*m+Z+ ddl,m-Z-  ee.          Z/deej0                 de1de2ej0                 fdZ3dede2e4e2ej0                 e2ej0                 f                  ddfdZ5dede6de6de2e6         fdZ7de2ee                  d e1dee4ej0                          fd!Z8dede6d"e2ej0                 d#e1de2e4e2ej0                 e2ej0                 f                  f
d$Z9dede2ej:                 de6d%e6de2ej0                 f
d&Z;	 	 	 	 dSde6d%e6d(e<dz  d)e=e6ef         dz  d e1dz  d*e1dz  dee4ej0                          fd+Z>	 	 	 dTdede6d%e6d,e1d-e1dz  d e1dz  de2ej0                 fd.Z?	 	 dUdede6d%e6d/e1d0e1dz  de2ej0                 fd1Z@dede6d%e6d2e1de1f
d3ZAdede6d%e6d2e6dej0        dz  f
d4ZBded5ejC        de6d%e6d2e6de<fd6ZDddddd7de6d8e2eE         de1d%e6dz  d9e2e6         dz  d:edz  d;edz  de2e6         fd<ZFddd=dede6d>e2e6         d:edz  d;edz  de2ej0                 fd?ZGdddd@dAdBdede6d%e6dz  d8e2eE         d9e2e6         dz  d:edz  d;edz  de1d#e1de2e4e2ej0                 e2ej0                 f                  fdCZHd@dAddddDde6d%e6dz  d8e2eE         de1d#e1dEe6d:edz  d;edz  dFe6dz  de2e4e2ej0                 e2ej0                 f                  fdGZI	 	 	 	 dVde6d%e6dz  dHe6de1d#e1dIe2eE         dz  dFe6dz  de2e4e2ej0                 e2ej0                 f                  fdJZJ	 	 	 dWdede6d%e6dz  dKe6de1d#e1d9e2e6         dz  de2e4e2ej0                 e2ej0                 f                  fdLZK	 	 	 dWde6d%e6dz  dKe6de1d#e1dFe6dz  de2e4e2ej0                 e2ej0                 f                  fdMZL	 	 	 	 	 dXdede6d%e6dz  d:edz  d;edz  de1dPe6dFe6dz  de2ej0                 fdQZM	 	 	 	 	 	 dYde6d%e6dz  dHe6d:edz  d;edz  de1d#e1dIe2eE         dz  dFe6dz  de2e4e2ej0                 e2ej0                 f                  fdRZNdS )Z    )Sequence)datetime)	getLogger)Any)generate)ColumnElementSelectand_funcor_selecttextupdate)AsyncSession)modelsschemas)settings)
tracked_db)embedding_client)VectorStoreError)EmbeddingCallPurpose)apply_filter)ILIKE_ESCAPE_CHARescape_ilike_pattern)embedding_call_purpose)VectorRecordget_external_vector_store   )get_or_create_sessionmessageslimitreturnc                     t                      }g }| D ]O}|j        |vrD|                    |j                   |                    |           t	          |          |k    r nP|S )z:Deduplicate messages by public_id, preserving input order.)set	public_idaddappendlen)r    r!   seenresultmsgs        8/DATA/AppData/hermes/projects/honcho/src/crud/message.py_deduplicate_messagesr-      sp     UUD#%F  =$$HHS]###MM#6{{e##M    dbsnippetsNc                     t                      }|D ]L\  }}g ||D ]@}t          |          }||v r|                     |           |                    |           AMdS )zFDetach snippet messages from the session, guarding against duplicates.N)r$   idexpunger&   )r/   r0   r)   matchescontextr+   obj_ids          r,   _expunge_snippetsr7   )   s     UUD$  'W'w' 	 	CWWF~~JJsOOOHHV	 r.   workspace_name	peer_namec                   K   t          t          j        j        j                                      t          j        j        j        |k                                  t          j        j        j        |k                                              }| 	                    |           d{V }d |
                                D             S )zGet all session names where a peer has any membership record.

    Any membership record (regardless of joined_at/left_at) grants visibility
    to all messages in that session.
    Nc                     g | ]
}|d          S )r    ).0rows     r,   
<listcomp>z*get_peer_session_names.<locals>.<listcomp>H   s    +++sCF+++r.   )r   r   session_peers_tablecsession_namewherer8   r9   distinctexecuteall)r/   r8   r9   stmtr*   s        r,   get_peer_session_namesrH   7   s       	v)+899	v)+:nL	M	M	v)+5B	C	C		 	 ::d########F++fjjll++++r.   base_conditionstoken_limitc                     t          t          j        j        t	          j        t          j        j                                      t          j        j                                                  	                    d                    j
        |                                  }t          t          j                                      |t          j        j        |j        j        k              
                    |j        j        |k              S )a  
    Helper function to apply token limit logic to a message query.

    Creates a subquery that calculates running sum of tokens for most recent messages
    and returns a select statement that joins with this subquery to limit results
    based on token count.

    Args:
        base_conditions: List of conditions to apply to the base query
        token_limit: Maximum number of tokens to include in the messages

    Returns:
        Select statement with token limit applied
    )order_byrunning_token_sum)r   r   Messager2   r   sumtoken_countoverdesclabelrC   subqueryjoinrA   rM   )rI   rJ   token_subquerys      r,   _apply_token_limitrW   K   s    &	NHV^/00T6>,1133T44U&''		
 	
 
	! 
  	v~	nfn/>3C3FF	G	G	~1[@	A	Ar.   matched_messagescontext_windowc                   K   |sg S i }|D ]0}|                     |j        g                               |           1i }|                                D ]\  }}|                    d            g }	|D ]m}
|
j        |z
  }|
j        |z   }|	r<||	d         d         dz   k    r'|	d         \  }}}|t          ||          g ||
f|	d<   T|	                    |||
gf           n|	||<   d |                                D             }t          t          j	                  
                    t          j	        j        |k              
                    t          |                               t          j	        j                                        t          j	        j                                                  }|                     |           d{V }i }|                                                                D ]0}|                     |j        g                               |           1g }|                                D ]J\  }}	|                    |g           }|	D ],\  }fd|D             }|                    ||f           -K|S )a  
    Group matched messages by session, merge overlapping context ranges, and fetch context.

    Takes a list of matched messages and builds conversation snippets by:
    1. Grouping matches by session name
    2. Sorting matches within each session by sequence number
    3. Merging overlapping context windows to avoid duplicate context
    4. Fetching the full context for each merged range from the database

    Args:
        db: Database session
        workspace_name: Name of the workspace
        matched_messages: List of messages that matched a search query
        context_window: Number of messages before/after each match to include

    Returns:
        List of tuples: (matched_messages_in_range, context_messages)
        Each tuple represents a snippet where context_messages includes all messages
        in the merged range (including the matched messages), ordered chronologically.
    c                     | j         S Nseq_in_session)ms    r,   <lambda>z(_build_merged_snippets.<locals>.<lambda>   s	    1#3 r.   )keyr   c           	      |    g | ]9\  }}t          t          j        j        |k    t	          d  |D                        :S )c              3   h   K   | ]-\  }}}t           j        j                            ||          V  .d S r\   )r   rN   r^   between)r=   	start_seqend_seq_s       r,   	<genexpr>z4_build_merged_snippets.<locals>.<listcomp>.<genexpr>   sQ        -	7A N199)WMM     r.   )r
   r   rN   rB   r   )r=   	sess_namemerged_rangess      r,   r?   z*_build_merged_snippets.<locals>.<listcomp>   si        %I} 	N'94 1>  	
 	
  r.   Nc                 >    g | ]}|j         cxk    rk    n n|S r<   r]   )r=   r+   rg   rf   s     r,   r?   z*_build_merged_snippets.<locals>.<listcomp>   sH           2====g===== ===r.   )
setdefaultrB   r'   itemssortr^   maxr   r   rN   rC   r8   r   rL   ascrE   scalarsrF   get)r/   r8   rX   rY   session_matchesr+   session_rangesrj   r4   rk   matchstartend
prev_startprev_endprev_matchessession_predicatescontext_stmtcontext_result
by_sessionr0   all_context_messagesrange_matchescontext_messagesrg   rf   s                           @@r,   _build_merged_snippetsr   p   s     4  	79O E E""3#3R88??DDDD NPN-3355 2 2	733444EG 	< 	<E(>9E&7C <-*;A*>*B!B!B5B25F2
Hl#&&*l*E*%b!! $$eS5'%:;;;;$1y!!  )7(<(<(>(>   	v~	v~,>	?	?	s&'	(	(	N'++--N)--//

 

	  ::l33333333N24J%%''++-- @ @c.33::3???? 	  %3$8$8$:$: ? ? 	=)~~i<<1> 	? 	?-Iw         /     
 OO],<=>>>>	? Or.   rB   c                 &  K   d |D             }t          | t          j        ||          |           d{V  |                     t	          d                     d{V  |                     t	          d          ||d           d{V  |                     t          t          j        j	                  
                    t          j        j        |k    t          j        j        |k                                  t          j        j	                                                                      d                     d{V pd	}g }t!          |d
          D ]p\  }}||z   }	t          j        ||j        |j        |j        pi |t)                      t+          |j                  |j        |		  	        }
|                    |
           q|                     |           |                                  d{V  	 t6          j        rLd |D             }|rTt;          t<          j        j         |d          5  tC          j"        |           d{V }ddd           n# 1 swxY w Y   ni }tG                      }t6          j$        j%        dk    pt6          j$        j&         }g }i }|D ]}
|'                    |
j(        g           }t!          |          D ]^\  }}t          j)        |
j        |
j(        |||
j        d|r|nd          }t+          |          }||f||<   |                    |           _g }|r;|                     |           | *                                 d{V  d |D             }|                                  d{V  ||r|                     tW          t          j)                  
                    t          j)        j,        -                    |                    .                    dt_          j0                    d	                     d{V  |                                  d{V  n|1                    d|          }g }t!          |          D ]a\  }}||         \  }}|j2         d| }|                    tg          |ti          |          |j2        |j        |j        d                     b|r	 |5                    ||           d{V  |r|                     tW          t          j)                  
                    t          j)        j,        -                    |                    .                    dt_          j0                    d	                     d{V  |                                  d{V  n# tl          $ r tn          8                    d           |r|                     tW          t          j)                  
                    t          j)        j,        -                    |                    .                    t          j)        j9        dz   t_          j0                                         d{V  |                                  d{V  Y ntt          $ r tn          ;                    d           |r|                     tW          t          j)                  
                    t          j)        j,        -                    |                    .                    t          j)        j9        dz   t_          j0                                         d{V  |                                  d{V  Y nw xY wn:# tt          $ r- tn          ;                    dt+          |          ||           Y nw xY w|S )a>  
    Bulk create messages for a session while maintaining order.

    Args:
        db: Database session
        messages: List of messages to create
        workspace_name: Name of the workspace
        session_name: Name of the session to create messages in

    Returns:
        List of created message objects
    c                 @    i | ]}|j         t          j                    S r<   )r9   r   SessionPeerConfigr=   messages     r,   
<dictcomp>z#create_messages.<locals>.<dictcomp>   s&    TTTW 9 ; ;TTTr.   )namepeers)sessionr8   NzSET LOCAL lock_timeout = '5s'zPSELECT pg_advisory_xact_lock(hashtext(:workspace_name), hashtext(:session_name)))r8   rB   r   r   )rw   )	rB   r9   content
h_metadatar8   r%   rP   
created_atr^   c                 h    i | ]/}|j         	|j                                         "|j        |j         0S r<   )r   stripr%   r   s     r,   r   z#create_messages.<locals>.<dictcomp>  sO          ?  (/'<'<'>'> !7?     r.   api)r8   parent_categorypgvectorpending)r   
message_idr8   rB   r9   
sync_state	embeddingc                     g | ]	}|j         
S r<   )r2   )r=   embs     r,   r?   z#create_messages.<locals>.<listcomp>O  s     E E EC E E Er.   synced)r   last_sync_atsync_attemptsr   rh   )r   rB   r9   )r2   r   metadataz:Vector store unavailable; leaving message vectors unsynced)r   r   z*Unexpected error upserting message vectorszUFailed to generate message embeddings for %s messages in workspace %s and session %s.)<r   r   SessionCreaterE   r   scalarr   r   rN   r^   rC   r8   rB   rL   rR   r!   	enumerater9   r   r   generate_nanoidr(   encoded_messager   r'   add_allcommitr   EMBED_MESSAGESr   r   MESSAGE_CREATEvaluer   batch_embedr   VECTOR_STORETYPEMIGRATEDrs   r%   MessageEmbeddingflushr   r2   in_valuesr   nowget_vector_namespacer   r   listupsert_manyr   loggerwarningr   	Exception	exception)r/   r    r8   rB   r   last_seqmessage_objectsoffsetr   message_seq_in_sessionmessage_objid_resource_dictembedding_dictexternal_vector_storestore_embeddings_in_postgresembedding_objectspending_embedding_data
embeddingschunk_positionr   embedding_objemb_idxembedding_ids	namespacevector_recordsr   	vector_ids                              r,   create_messagesr      sh	     & UT8TTTE

%<uEEE%          **T9::
;
;;;;;;;;
**^	
 	
 *<HH	         ii6>011U-?+|;  Xfn388::;;U1XX
 
 	
 	
 	
 	
 	
 	
 		   -/O$XQ777 , ,!)F!2n%'O'-2)%''G344)1

 

 

 	{++++JJ ))++U
" L	.   .     
   
$+(7=#1$)    
 ,<+G(, , & & & & & &N               "$$=$?$?!
 %*j8 6,55 ) @BIK". < <+//0ErJJ
1::1F1F < <-NI$*$; + 3#.#8'5%1"-"7#,/K"U))QU% % %M ""344G7Ey6Q*73%,,];;;;<  (*M  F

,---hhjj        E E3D E E E))++ %,  
&**v677v69==mLLMM'/)-*+             ))++%%%%%%% 2FF~ 	
 68$-.?$@$@  LGS0Fw0O-NI#&> D DN D DI"))$(&*9oo.1n030@-0]& &  
 
 
 
 " ..-.3??%~         ) 
."$** &v'> ? ?!&v'>'A'E'Em'T'T!U!U!'/71523 "( "" ""# #        #%))++-------+ . . .X   ) 
."$** &v'> ? ?!&v'>'A'E'Em'T'T!U!U!'282I2W&'3(15 "( "" ""# #        #%))++-------$ . . .(()UVVV( 
."$** &v'> ? ?!&v'>'A'E'Em'T'T!U!U!'282I2W&'3(15 "( "" ""# #        #%))++-------.  
 
 
c  		
 	
 	
 	
 	

 sj   =<] 9I ]  I$$] 'I$(I ] 	CV ] C]0] 2C]] ]] 4^^Freversefiltersmessage_count_limitc                   K   t           j        j        | k    t           j        j        |k    g}| t	          t           j                  j        | }t          |t           j        |          }|                    t           j        j        	                                          
                    |          }|r8|                    t           j        j        	                                          }n|                    t           j        j                                                  }nH|t          ||          }t          |t           j        |          }|r7|                    t           j        j        	                                          }n|                    t           j        j                                                  }n t	          t           j                  j        | }t          |t           j        |          }|r7|                    t           j        j        	                                          }n6|                    t           j        j                                                  }|S )a  
    Get messages from a session. If token_limit is provided, the n most recent messages
    with token count adding up to the limit will be returned. If message_count_limit is provided,
    the n most recent messages will be returned. If both are provided, message_count_limit will be
    used.

    Args:
        workspace_name: Name of the workspace
        session_name: Name of the session
        reverse: Whether to reverse the order of messages
        filters: Filter to apply to the messages
        token_limit: Maximum number of tokens to include in the messages
        message_count_limit: Maximum number of messages to include

    Returns:
        Select statement for the messages
    )r   rN   r8   rB   r   rC   r   rL   r2   rR   r!   rq   rW   )r8   rB   r   r   rJ   r   rI   rG   s           r,   get_messagesr     s     6 	%7#|3O &+vfn%%+_=D&.':: }}V^.335566<<=PQQ  	:==!2!7!7!9!9::DD==!2!6!6!8!899DD		 !/;??D&.'::  	:==!2!7!7!9!9::DD==!2!6!6!8!899DD ,vfn%%+_=D&.':: 	:==!2!7!7!9!9::DD==!2!6!6!8!899DKr.   start_idend_idc                   K   |dk     s|||k    s|dk    rg S t           j        j        |k    t           j        j        |k    g}|rJ|                    t          t           j        j        |k    t           j        j        |k                          n(|                    t           j        j        |k               |r5t          ||          }|                    t           j        j                  }n! t          t           j                  j
        | }|                     |           d{V }t          |                                                                          S )aO  
    Get messages from a session by primary key ID range.
    If end_id is not provided, all messages after and including start_id will be returned.
    If start_id is not provided, start will be beginning of session.

    Note: list is *inclusive* of the end_id message and start_id message.

    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session
        start_id: Primary key ID of the first message to return
        end_id: Primary key ID of the last message (exclusive)

    Returns:
        List of messages
    r   N)r   rN   r8   rB   r'   r
   r2   rW   rL   r   rC   rE   r   rr   rF   )	r/   r8   rB   r   r   rJ   rI   rG   r*   s	            r,   get_messages_id_ranger     sH     2 !||*F0B0BfPQkk	 	%7#|3O  >"h.0AF0JKK	
 	
 	
 	
 	v~0H<=== >!/;??}}V^.//+vfn%%+_=::d########F  $$&&'''r.   rf   rg   c                   K   |dk     s|||k    rg S t           j        j        |k    t           j        j        |k    g}|J|                    t          t           j        j        |k    t           j        j        |k                         n(|                    t           j        j        |k                t          t           j                  j        | 	                    t           j        j        
                                          }|                     |           d{V }t          |                                                                          S )a  
    Get messages from a session by seq_in_session range.

    This is useful for getting the last N messages in a session.

    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session
        start_seq: Sequence number of the first message to return (inclusive)
        end_seq: Sequence number of the last message to return (inclusive)

    Returns:
        List of messages ordered by seq_in_session
    r   N)r   rN   r8   rB   r'   r
   r^   r   rC   rL   rq   rE   r   rr   rF   )r/   r8   rB   rf   rg   rI   rG   r*   s           r,   get_messages_by_seq_ranger   '  s;     , 1}},W1D1D	 	%7#|3O
 -:-8 	
 	
 	
 	
 	v~<	IJJJ	v~		!	&./3355	6	6 	 ::d########F  $$&&'''r.   r   c                   K   t          t          j        j                                      t          j        j        |k                                  t          j        j        |k                                  t          j        j        |k              }|                     |           d{V }|t          |          ndS )a	  
    Get the sequence number of a message within a session.

    Args:
        db: Database session
        session_name: Name of the session
        message_id: Primary key ID of the message

    Returns:
        The sequence number of the message (1-indexed)
    Nr   )
r   r   rN   r^   rC   r8   rB   r2   r   int)r/   r8   rB   r   rG   seqs         r,   get_message_seq_in_sessionr   Y  s      $ 	v~,--	v~,>	?	?	v~*l:	;	;	v~ J.	/	/	 	 IIdOO++++++C3s888A-r.   c                 z  K   t          t          j                                      t          j        j        |k                                  t          j        j        |k                                  t          j        j        |k              }|                     |           d {V }|                                S r\   )	r   r   rN   rC   r8   rB   r%   rE   scalar_one_or_none)r/   r8   rB   r   rG   r*   s         r,   get_messager   t  s       	v~	v~,>	?	?	v~*l:	;	;	v~':5	6	6	 	 ::d########F$$&&&r.   r   c                    K   t          | |||           d {V }|t          d          |j        |j        |_        |                                  d {V  |S )N)r8   rB   r   z,Message not found or does not belong to user)r   
ValueErrorr   r   r   )r/   r   r8   rB   r   honcho_messages         r,   update_messager     s       '
%!	        N GHHH$$+$4!
))++r.   rB   allowed_session_names
after_datebefore_datequery_embeddingr   r   r   c                  K   t                      }|g S |                    d|           }i }	|r||	d<   n	|d|i|	d<   |dup|du}
|
rdnd}|                    ||||z  |	r|	nddg           d{V }|sg S i }|D ]'}|j                            d          }|r	||vrd||<   (t          |                                          }|sg S |S )	zQuery the external vector store and return ordered message IDs.

    Multiple vector records can map to the same message (chunked embeddings),
    so we oversample from the vector store and deduplicate by message_id.
    Nr   rB   in      r   )top_kr   include_attributes)r   r   queryr   rs   r   keys)r8   r   r!   rB   r   r   r   r   r   vector_filtershas_date_filters
oversamplevector_resultsr)   vrmidmessage_idss                    r,   _search_messages_externalr     s[      677$	%::9nUUI%'N G)5~&&		**.0E)F~&
 "-HD1H&-AJ066j "0:d(> 7        N  	 D  kool++ 	3d??DItyy{{##K 	r.   r   r   r   c                J  K   t          t          j                                      t          j        j                            |                                        t          j        j        |k              }|r(|                    t          j        j        |k              }|r(|                    t          j        j        |k              }|                     |           d{V }d |	                                
                                D             fd|D             S )z7Fetch messages by ID, preserving the supplied ordering.Nc                     i | ]
}|j         |S r<   )r%   )r=   r+   s     r,   r   z*_fetch_messages_by_ids.<locals>.<dictcomp>  s    KKKScmSKKKr.   c                 (    g | ]}|v |         S r<   r<   )r=   r   messages_by_ids     r,   r?   z*_fetch_messages_by_ids.<locals>.<listcomp>  s(    PPPC#:O:ON3:O:O:Or.   )r   r   rN   rC   r%   r   r8   r   rE   rr   rF   )r/   r8   r   r   r   
fetch_stmtr*   r   s          @r,   _fetch_messages_by_idsr     s      	v~	v~'++K88	9	9	v~,>	?	? 
  O%%fn&?:&MNN
 P%%fn&?;&NOO
::j))))))))FKKFNN4D4D4H4H4J4JKKKNPPPP;PPPPr.   
      )r   r   r   r!   rY   c                  K   t          t          j                                      t          j        t          j        j        t          j        j        k                                  t          j        j        |k              	                    t          j        j
                            |                                        |dz            }	|r)|	                    t          j        j        |k              }	n9|7|	                    t          j        j                            |                    }	|r(|	                    t          j        j        |k              }	|r(|	                    t          j        j        |k              }	|                     |	           d{V }
t#          |
                                                                |          }t)          | |||           d{V S )z?Run semantic message search against pgvector-backed embeddings.r   N)r   r   rN   rU   r   r%   r   rC   r8   rL   r   cosine_distancer!   rB   r   r   rE   r-   rr   rF   r   )r/   r8   rB   r   r   r   r   r!   rY   
match_stmtr*   rX   s               r,   _search_messages_pgvectorr    s     $ 	v~	#N$(?(JJ

 

 
v&5G	H	H	&)3CCOTT	U	U	uqy		   
%%#0L@
 


 
	*%%#0445JKK
 

  O%%fn&?:&MNN
 P%%fn&?;&NOO
::j))))))))F,V^^-=-=-A-A-C-CUKK'
N,n        r.   )r!   rY   r   r   observeroperation_namer  c                ,  K   d}	|rY|sWt          | d          4 d{V }
t          |
| |           d{V }	ddd          d{V  n# 1 d{V swxY w Y   |	sg S t          j        j        dk    rt          j        j        rt          | ||||	||           d{V }|sg S t          |          4 d{V }
t          |
| |||           d{V d|         }t          |
| ||           d{V }t          |
|           |cddd          d{V  S # 1 d{V swxY w Y   t          |          4 d{V }
t          |
| |||	||||	  	         d{V }t          |
|           |cddd          d{V  S # 1 d{V swxY w Y   dS )zRun semantic message search with optional temporal filters.

    When observer is provided and session_name is None, results are
    scoped to sessions the observer has any membership record in.
    Nz.peer_scoper   r   r   )r   r   r   r   r!   rY   )r   rH   r   r   r   r   r   r   r   r7   r  )r8   rB   r   r!   rY   r  r   r   r  r   r/   r   rX   r0   s                 r,   _semantic_search_messagesr     s      $ /3  <<<== 	 	 	 	 	 	 	*@NH+ + % % % % % %!	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 % 	I!Z//H4I4R/5%"7!#
 
 
 
 
 
 
 
 
  	In-- 	 	 	 	 	 	 	,") +         uf  4N$4n       H b(+++	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	  .))       R2+"7!#)

 

 

 

 

 

 

 

 

 	"h'''                             s6   A
AA;AD
D$'D$ 0F
FFr   r   c           	         K   ||}nRt          t          j        j        |           5  t	          j        |           d{V }ddd           n# 1 swxY w Y   t          | ||||d|           d{V S )a  
    Search for messages using semantic similarity and return conversation snippets.

    Each result includes matched messages plus surrounding context. Overlapping
    snippets within the same session are merged to avoid repetition.

    Args:
        workspace_name: Name of the workspace
        session_name: Name of the session (optional)
        query: Search query text
        limit: Maximum number of matching messages to return
        context_window: Number of messages before/after each match to include
        embedding: Optional pre-computed embedding
        observer: When provided and session_name is None, scope results
            to sessions this peer belongs to

    Returns:
        List of tuples: (matched_messages, context_messages)
        Each snippet may contain multiple matches if they were close together.
        Context messages are ordered chronologically and include the matched messages.
    Nr8   zmessage.search_messages)r   r!   rY   r  r  r   r   SEARCH_MESSAGESr   r   embedr  )r8   rB   r   r!   rY   r   r  r   s           r,   search_messagesr  h  s     < #
 $ 06)
 
 
 	B 	B %5$:5$A$AAAAAAAO		B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B
 +'%0            AAAr   c                 D  K   t          |          }t          t          j                                      t          j        j        |k                                  t          j        j                            d| dt                              	                    t          j        j
                                                                      |          }|r)|                    t          j        j        |k              }n9|7|                    t          j        j                            |                    }|                     |           d{V }	t!          |	                                                                          }
t'          | ||
|           d{V S )z5Internal implementation of exact-text message search.%)escapeN)r   r   r   rN   rC   r8   r   iliker   rL   r   rR   r!   rB   r   rE   r   rr   rF   r   )r/   r8   rB   r   r!   rY   r   escaped_textr  r*   rX   s              r,   _grep_messages_internalr    s~      (--Lv~	v~,>	?	?	N"(()<\)<)<)<EV(WW

 

 
&.+0022	3	3	u   
%%fn&A\&QRR

		*%%N'++,ABB
 

 ::j))))))))FFNN,,002233'
N,n        r.   c           
      >  K   t          d          4 d{V }d}|r/|s-t          || |           d{V }|sg cddd          d{V  S t          || |||||           d{V }t          ||           |cddd          d{V  S # 1 d{V swxY w Y   dS )a6  
    Search for messages containing specific text (case-insensitive substring match).

    Unlike semantic search, this finds EXACT text matches. Useful for finding
    specific names, dates, phrases, or keywords.

    Args:
        workspace_name: Name of the workspace
        session_name: Name of the session (optional - searches all sessions if None)
        text: Text to search for (case-insensitive)
        limit: Maximum number of matching messages to return
        context_window: Number of messages before/after each match to include
        observer: When provided and session_name is None, scope results
            to sessions this peer belongs to

    Returns:
        List of tuples: (matched_messages, context_messages)
        Each snippet may contain multiple matches if they were close together.
    zmessage.grep_messagesN)r   )r   rH   r  r7   )	r8   rB   r   r!   rY   r  r/   r   r0   s	            r,   grep_messagesr    s     6 122       b $ 	L 	*@NH+ + % % % % % %! )               1"7
 
 
 
 
 
 
 
 
 	"h''')                             s   !B-B
BB   rR   orderc                   K   d}|r|st          | ||           d{V }|sg S t          t          j                                      t          j        j        |k              }	|r)|	                    t          j        j        |k              }	n9|7|	                    t          j        j                            |                    }	|r(|	                    t          j        j        |k              }	|r(|	                    t          j        j        |k              }	|dk    r7|		                    t          j        j        
                                          }	n6|		                    t          j        j                                                  }	|	                    |          }	|                     |	           d{V }
t          |
                                                                          S )ap  
    Get messages within a date range.

    Args:
        db: Database session
        workspace_name: Name of the workspace
        session_name: Name of the session (optional - searches all sessions if None)
        after_date: Return messages after this datetime
        before_date: Return messages before this datetime
        limit: Maximum messages to return
        order: Sort order - 'asc' for oldest first, 'desc' for newest first
        observer: When provided and session_name is None, scope results
            to sessions this peer belongs to

    Returns:
        List of messages within the date range
    Nrq   )rH   r   r   rN   rC   r8   rB   r   r   rL   rq   rR   r!   rE   r   rr   rF   )r/   r8   rB   r   r   r!   r  r  r   rG   r*   s              r,   get_messages_by_date_ranger    s     8 !  &<'
 '
 !
 !
 !
 !
 !
 !
 % 	I&.!!''(E(WXXD Rzz&.5EFF		*zz&.599:OPPQQ Czz&.3zABB Dzz&.3{BCC~~}}V^6::<<==}}V^6;;==>>::eD::d########F  $$&&'''r.   c	                    K   ||}	nRt          t          j        j        |           5  t	          j        |           d{V }	ddd           n# 1 swxY w Y   t          | ||	||||d|	  	         d{V S )a  
    Search for messages using semantic similarity with optional date filtering.

    Combines the power of semantic search with time constraints. Use after_date
    to find recent mentions, or before_date to find what was said before a certain point.

    Args:
        workspace_name: Name of the workspace
        session_name: Name of the session (optional)
        query: Search query text
        after_date: Only return messages after this datetime
        before_date: Only return messages before this datetime
        limit: Maximum number of matching messages to return
        context_window: Number of messages before/after each match to include
        embedding: Optional pre-computed embedding for the query
        observer: When provided and session_name is None, scope results
            to sessions this peer belongs to

    Returns:
        List of tuples: (matched_messages, context_messages)
        Each snippet may contain multiple matches if they were close together.
    Nr
  z message.search_messages_temporal)r   r   r   r!   rY   r  r  r  )
r8   rB   r   r   r   r!   rY   r   r  r   s
             r,   search_messages_temporalr  -  s     B #
 $ 06)
 
 
 	B 	B %5$:5$A$AAAAAAAO		B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B
 +'%9
 
 
 
 
 
 
 
 
 
r  )FNNN)r   NN)r   N)r   r   NN)r   r   N)NNr  rR   N)NNr   r   NN)Ocollections.abcr   r   loggingr   typingr   nanoidr   r   
sqlalchemyr   r	   r
   r   r   r   r   r   sqlalchemy.ext.asyncior   srcr   r   
src.configr   src.dependenciesr   src.embedding_clientr   src.exceptionsr   src.telemetry.eventsr   src.utils.filterr   src.utils.formattingr   r   src.utils.typesr   src.vector_storer   r   r   r   __name__r   rN   r   r   r-   tupler7   strrH   rW   r   MessageCreater   booldictr   r   r   r   r   MessageUpdater   floatr   r   r  r  r  r  r  r  r  r<   r.   r,   <module>r6     s}   $ $ $ $ $ $                   . . . . . . S S S S S S S S S S S S S S S S S S S S / / / / / /               ' ' ' ' ' ' 1 1 1 1 1 1 + + + + + + 5 5 5 5 5 5 ) ) ) ) ) ) H H H H H H H H 2 2 2 2 2 2 D D D D D D D D * * * * * *	8		v~&/2	&.    $U4+?fnAU+U%V W	   ,,, , 
#Y	, , , ,("-,-"<?"E&.!"" " " "Jaaa 6>*a 	a
 
%V^$d6>&::
;<a a a aH\\7()\ \ 	\
 
&.\ \ \ \D !%)"&*? ??? D[? #s(^d"	?
 t? t? E&.!"? ? ? ?L "/( /(/(/( /( 	/(
 $J/( t/( 
&./( /( /( /(l /( /(/(/( /( 	/(
 4Z/( 
&./( /( /( /(d... . 	.
 	. . . .6''' ' 	'
 ^d' ' ' ' "  	
  
   :  $.2"&#'6 6 66%[6 6
 *6  9t+6 46 D6 
#Y6 6 6 6| #'#'Q Q QQQ cQ
 4Q DQ 
&.Q Q Q Q> /3"&#'/ / /// */
 %[/  9t+/ 4/ D/ / / 
%V^$d6>&::
;</ / / /n "&#'E E EE*E %[	E
 E E E 4E DE DjE 
%V^$d6>&::
;<E E E EX $(1 11*1 1 	1
 1 E{T!1 Dj1 
%V^$d6>&::
;<1 1 1 1r .2" """ *" 	"
 " "  9t+" 
%V^$d6>&::
;<" " " "R / //*/ / 	/
 / Dj/ 
%V^$d6>&::
;</ / / /l #'#'7( 7(7(7( *7( 4	7(
 D7( 7( 7( Dj7( 
&.7( 7( 7( 7(| #'#'$(6 66*6 6 4	6
 D6 6 6 E{T!6 Dj6 
%V^$d6>&::
;<6 6 6 6 6 6r.   