
    yjn                    8   U 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 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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!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-m.Z.m/Z/  ej0        e1          Z2dZ3dej4        dej4        fdZ5de6e7e	f         fdZ8de6e7e	f         fdZ9de6e7e	f         fdZ:de6e7e	f         fdZ;de	de<de<fdZ= ej>                    Z?ej>        e@e7e7e7f         e jA        f         eBd<    e jA                    ZCd e7d!e7d"e7de jA        fd#ZDe G d$ d%                      ZEe G d& d'                      ZF	 dd(e7d)e<dz  de@e7e<eGf         fd*ZHd(e7dd+fd,ZIdd-e7d)e<dz  de7fd.ZJ	 dd-e7d/e7d)e<dz  de7fd0ZKi d1d1d2d3d4d5d6 e9            d7id4gd8d9d:d:d;d3d4d5d< e:            d7id4gd8d9d=d=d>d3d4d5d? e;            d7id4gd8d9d@d@dAd3d-d5dBdCdDid7id-gd8d9dEdEdFd3i dGd9dHdHdId3dDdJdKdLdMdNdOdPdQgd8d9dRdRdSd3dTd5dCdDidUdVidTgd8d9dWdWdXd3dDdYdKdLdZd[dOd\dQgd8d9d]d]d^d3dDd_dKdLd`d[dOdLdadbdOdcddgd8d9dededfd3dDdgdKdDdhdKdLdidNdOdDdjdkgdldkdmdndGd9dododpd3dDdqdKdDdrdKdDdsdKdLdtd[dOdLdudbdOdvdQgd8d9dwdwdxd3dLdyd[dOdzd{d|dOd}dGd9d~d~dd3ddLdyd[dOidGd9dddd3ddDddgdddmidGd9dddd3i dGd9dddd3dd5dCdDiddVidgd8d9dddd3ddDddKidgd8d9ddd3i dGd9ddd3dDddKdDg ddddmddgd8d9dZLe6e7e6e7e	f         f         eBd<   eLdH         eLdW         eLdR         eLd]         eLde         eLdo         eLd         gZMeNe6e7e	f                  eBd<   eLdH         eLdW         gZOeNe6e7e	f                  eBd<   eLd         eLdw         eLd~         eLdH         eLd         eLd1         eLd         eLd@         eLdW         eLdR         eLd         eLd         gZPeNe6e7e	f                  eBd<   eLdw         eLdH         eLdW         eLd:         eLd         eLd@         gZQeNe6e7e	f                  eBd<   eLdw         eLdH         eLdW         eLd=         eLd@         gZReNe6e7e	f                  eBd<   	 	 dd4eNej4                 d!e7d"e7de7dz  d e7dTeNe<         de7de7dz  de7dz  deFfdZS	 	 dded e7de7dz  d"e7dz  de<deNejT                 fdZU	 	 dd e7d!e7d"e7dQe7de<deNe7         dz  deNeV         dz  de+fdZW	 dded e7de7dz  dTeNe7         d!e7dz  deNejT                 fdZX	 dd e7de7dz  d"e7d!e7dz  de6e7eNe7         f         f
dZYe G d d                      ZZdddeZde6e7e	f         de7dz  dd+fdZ[deZde6e7e	f         dd+fdZ\deZde6e7e	f         dd+fdZ]deZde6e7e	f         dd+fdZ^deZde6e7e	f         dd+fdZ_deZde6e7e	f         dd+fdZ`deZde6e7e	f         dd+fdZadeZde6e7e	f         dd+fdZbdeZde6e7e	f         dd+fdZcdeZde6e7e	f         dd+fdZdde7dz  de7dedz  e7z  fdZedeZde6e7e	f         dd+fdÄZfdeZde6e7e	f         dd+fdĄZgdeZde6e7e	f         de7fdńZhdeZde6e7e	f         de7fdƄZideZde6e7e	f         de7fdǄZjdeZde6e7e	f         de7fdȄZkdeZde6e7e	f         dd+fdɄZldeZde6e7e	f         de7fdʄZmdeZde6e7e	f         de7fd˄ZndeNe@eNejT                 eNejT                 f                  dke7de7fd̈́ZodeZde6e7e	f         de7fd΄Zpi d1e\d:e]d=e^d@e_dEe`dHeadRebdWecd]eddeefdoegdwehd~eidejdekdeldemenepdZqe6e7eeZe6e7e	f         ge	f         f         eBd<   	 	 	 	 	 	 	 	 dd e7d!e7d"e7de7dz  deNejT                 dz  deGde<dedz  de7dz  de7dz  de7dz  dee7e6e7e	f         ge	f         fdՄZrddde7deVde7de6e7e	f         deGde<de<de7dz  ddfdބZsdde7de<fd߄Ztdde7dz  de<dz  fdZudS )    N)Callable)	dataclass)datetime)Anycast)ValidationError)select)AsyncSession)crudmodelsschemas)settings)
tracked_db)embedding_client)Document)ResolvedConfiguration) AgentToolConclusionsCreatedEvent AgentToolConclusionsDeletedEventAgentToolPeerCardUpdatedEventEmbeddingCallPurposeemit)
summarizer)format_new_turn_with_timestamputc_now_iso)Representation)
ToolResultembedding_call_purposeget_current_iteration(   obsreturnc                 `    |                      d| j                                        i          S )zNReturn an observation input with content normalized for persistence/embedding.content)update)
model_copyr#   strip)r    s    =/DATA/AppData/hermes/projects/honcho/src/utils/agent_tools.py_normalized_observation_inputr(   %   s+     >>)S[->->-@-@!A>BBB    c            
      d    ddddg ddddddid	d
dddidd
dddidd
dg ddddg ddddS )NstringzThe observation contenttypedescription)explicit	deductive	inductivecontradictionzLevel: 'explicit' for direct facts, 'deductive' for logical necessities, 'inductive' for patterns, 'contradiction' for conflicting statementsr-   enumr.   arrayr-   zDocument IDs of source or premise observations. Required and must be non-empty for deductive, inductive, and contradiction observations.r-   itemsr.   z7(For deductive) Human-readable premise text for displayzD(For inductive/contradiction) Human-readable source text for display
preferencebehaviorpersonalitytendencycorrelationz5(For inductive only) Type of pattern being identifiedhighmediumlowz[(For inductive only) Confidence level: 'high' for 5+ sources, 'medium' for 3-4, 'low' for 2)r#   level
source_idspremisessourcespattern_type
confidence rH   r)   r'   _base_observation_propertiesrI   ,   s     4
 

   +
 
 h'"	
 
 h'T
 
 h'a
 
    S

 

 ---2	
 
c9 9 9r)   c                      dt                      ddgdddddiiidd	gd
ddiddd
ddidddddddddiiig dd
ddiddd
ddidddddddddiiiddgd
ddiddd
ddidddddgdS )Nobjectr#   rB   F
propertiesconstr0   rC   rD   r5   r-   r+      )r-   r7   minItems)rC   rD   )requiredrL   )ifthenr1   )rC   rE   rF   rG      )rC   rE   r2   rE   )r-   rL   rP   additionalPropertiesallOf)rI   rH   r)   r'    _generic_observation_item_schemarV   i   s   244( % $g/E%FG!-z : %,&,h%7()' ' %,&,h%7()% %# #  & $g/E%FG! ! ! %,&,h%7()' ' %,&,h%7()$ $# #  0 $g/I%JK!-y 9 %,&,h%7()' ' %,&,h%7()$ $# #  U<
B B Br)   c                  >    dddddddiddd	dddidd
d	dg dddS )NrK   r+   z6The deductive conclusion as a self-contained statementr,   r5   r-   rN   zJRequired non-empty list of source observation IDs supporting the deductionr-   r7   rO   r.   zERequired human-readable premise text matching the source observations)r#   rC   rD   Fr-   rL   rP   rT   rH   rH   r)   r'   "_deductive_observation_item_schemarZ      sx     !W 
   (+k	    (+f	 
 
$ :99 %+  r)   c            	      Z    dddddddiddd	dddidd
d	dg ddddg ddddg dddS )NrK   r+   zEThe inductive pattern or generalization as a self-contained statementr,   r5   r-   rS   zKRequired list of at least two source observation IDs supporting the patternrX   zFRequired human-readable evidence text matching the source observationsr8   zRequired pattern categoryr3   r>   z1Required confidence level based on evidence count)r#   rC   rE   rF   rG   FrY   rH   rH   r)   r'   "_inductive_observation_item_schemar\      s     !f 
   (+l	    (+g	  !    ;
 
 !111R 9!
 !
D WVV %K& & &r)   valuedefaultc                 `    	 t          |           S # t          t          t          f$ r |cY S w xY w)zCoerce a tool input value to int, returning default on failure.

    LLMs sometimes pass non-numeric strings (e.g. 'Infinity') for integer
    parameters which would crash ``min()`` comparisons.
    )int	TypeError
ValueErrorOverflowError)r]   r^   s     r'   	_safe_intrd      s>    5zzz=1   s    --_observation_locksworkspace_nameobserverobservedc                    K   | ||f}t           4 d{V  t                              |          }|t          j                    }|t          |<   |cddd          d{V  S # 1 d{V swxY w Y   dS )u  
    Get or create a lock for a specific workspace/observer/observed combination.

    This ensures that concurrent tool executors operating on the same observation
    space share a lock, preventing race conditions during document creation.

    The lock is stored as a weak reference — it stays alive as long as at least
    one ToolContext (via create_tool_executor) holds a strong reference. Once all
    executors for a key finish and are garbage collected, the entry is
    automatically removed from the registry.

    Args:
        workspace_name: Workspace identifier
        observer: The observing peer
        observed: The peer being observed

    Returns:
        An asyncio.Lock shared by all executors for this combination
    N)_registry_lockre   getasyncioLock)rf   rg   rh   keylocks        r'   get_observation_lockrp     s	     , 8X
.C        !%%c**<<>>D&*s#                             s   ;A##
A-0A-c                   (    e Zd ZU dZeed<   eed<   dS )ObservationFailurez9Records a single observation that failed during creation.content_previewerrorN)__name__
__module____qualname____doc__str__annotations__rH   r)   r'   rr   rr   ,  s+         CCJJJJJr)   rr   c                   J    e Zd ZU dZeed<   ee         ed<   ee         ed<   dS )ObservationsCreatedResultz+Result of a batch create_observations call.created_countcreated_levelsfailedN)	ru   rv   rw   rx   r`   rz   listry   rr   rH   r)   r'   r|   r|   4  sF         55I#$$$$$$r)   r|   output	max_charsc                     |t           j        j        }t          |           }||k    r| |dfS | d|         d|dd|ddz   }||dfS )aI  Truncate tool output to prevent token explosion.

    Returns (text, original_chars, was_truncated). Callers thread the
    truncation signal into `ToolResult.metadata` so
    `AgentToolCallCompletedEvent` can report `was_truncated` and
    `result_chars_before_truncation` instead of always emitting them as
    None/False.
    NFz

[OUTPUT TRUNCATED - showing ,z of z characters]T)r   LLMMAX_TOOL_OUTPUT_CHARSlen)r   r   original_chars	truncateds       r'   _truncate_tool_outputr   =  sy     L6	[[N""~u,,z	z
\Y
\
\
\n
\
\
\
\	]  nd**r)   zstr | ToolResultc                 X    t          |           \  }}}|s|S t          |d|d          S )a~  Run `_truncate_tool_output` and wrap in `ToolResult` only when the
    output was actually clamped, so the truncation signal reaches the
    `AgentToolCallCompletedEvent` emitter (which reads `was_truncated` /
    `result_chars_before_truncation` from `ToolResult.metadata`). Returns a
    bare `str` in the common no-truncation case to keep the handler
    contract unchanged.
    T)was_truncatedresult_chars_before_truncationr#   metadata)r   r   )r   r#   r   r   s       r'   _maybe_truncated_resultr   T  sP     .C6-J-J*G^] !.<
 
   r)   r#   c                 l    |t           j        j        }t          |           |k    r| S | d|         dz   S )zBTruncate individual message content (simple beginning truncation).N...)r   r   MAX_MESSAGE_CONTENT_CHARSr   )r#   r   s     r'   _truncate_message_contentr   h  s<    L:	
7||y  :I:&&r)   patternc                    ddl }|t          j        j        }t	          |           |k    r| S |                    |                    |          | |j                  }|s| d|         dz   S |                                }|	                                }||z
  }||z
  }|dz  }	||	z
  }
t          d||	z
            }t          t	          |           ||
z             }|dk    rt          t	          |           |          }n3|t	          |           k    r t          dt	          |           |z
            }| ||         }|dk    rdnd}|t	          |           k     rdnd}| | | S )zExtract snippet around a regex pattern match.

    For grep/exact text search, finds the pattern and extracts context around it.
    r   Nr   rS    )rer   r   r   r   searchescape
IGNORECASEstartendmaxmin)r#   r   r   r   matchmatch_start	match_end	match_len	remainingbeforeafterr   r   snippetprefixsuffixs                   r'   _extract_pattern_snippetr   q  s~    IIIL:	
7||y  IIbii(('2=AAE +z	z"U**++--K		I K'II%I!^FE;'((E
c'llI-
.
.C zz#g,,	**	G		As7||i/00eCi GaiiUURFCLL((UUbF'g'v'''r)   create_observationsa  Create observations at any level: explicit (facts), deductive (logical necessities), inductive (patterns), or contradiction (conflicting statements). For deductive, inductive, and contradiction observations, missing or empty source_ids are invalid and will be rejected.rK   observationsr5   zList of observations to create)r-   r.   r7   )r-   rL   rP   )namer.   input_schemacreate_observations_deductivezCreate new deductive observations discovered while answering the query. Every observation must include non-empty source_ids and premise text. Use this only for novel deductions grounded in existing observations.z,List of new deductive observations to createcreate_observations_inductivezCreate new inductive observations discovered while answering the query. Every observation must include source_ids, source text, pattern_type, and confidence. Use this only for patterns supported by multiple observations.z,List of new inductive observations to createupdate_peer_cardzUpdate the peer card with durable profile facts about the observed peer. Only include stable biographical facts, standing instructions, and long-lived preferences/traits. Do not include one-off conclusions, temporary events, or duplicate entries.znComplete deduplicated peer card list (max 40 entries). Each entry should be a concise standalone profile fact.r-   r+   get_recent_historyzPRetrieve recent conversation history to get more context about the conversation.)r-   rL   search_memoryzSearch for observations in memory using semantic similarity. Use this to find relevant information about the peer when you need to recall specific details.zSearch query textr,   integerz=(Optional) number of results to return (default: 20, max: 40)   )r-   r.   r^   )querytop_kr   get_observation_contextzRetrieve messages for given message IDs along with surrounding context. Takes message IDs (from an observation's message_ids field) and retrieves those messages plus the messages immediately before and after each one to provide conversation context.message_idszZList of message IDs to retrieve (get these from observation.message_ids in search results)r6   search_messagesa   Search for messages using semantic similarity and retrieve conversation snippets. Returns matching messages with surrounding context (2 messages before and after). Nearby matches within the same session are merged into a single snippet to avoid repetition.z+Search query text to find relevant messageszDMaximum number of matching messages to return (default: 10, max: 20)
   )r   limitgrep_messageszSearch for messages containing specific text (case-insensitive). Unlike semantic search, this finds EXACT text matches. Use for finding specific names, dates, phrases, or keywords mentioned in conversations. Returns messages with surrounding context.z5Text to search for (case-insensitive substring match)z1Maximum messages to return (default: 10, max: 30)zBNumber of messages before/after each match to include (default: 2)rS   )textr   context_windowr   get_messages_by_date_rangezGet messages from a specific date range. Use this to find what was discussed during a particular time period, or to compare information before vs after a date. Essential for knowledge update questions.zNStart date (ISO format, e.g., '2024-01-15'). Returns messages after this date.z9End date (ISO format). Returns messages before this date.z1Maximum messages to return (default: 20, max: 50)ascdesczKSort order: 'asc' for oldest first, 'desc' for newest first (default: desc))r-   r4   r.   r^   )
after_datebefore_dater   ordersearch_messages_temporalaY  Semantic search for messages with optional date filtering. Combines the power of semantic search with time constraints. Use after_date to find recent mentions of a topic, or before_date to find what was said about something before a certain point. Best for knowledge update questions where you need to find the MOST RECENT discussion of a topic.zSemantic search queryzEOnly return messages after this date (ISO format, e.g., '2024-01-15')z2Only return messages before this date (ISO format)z1Maximum messages to return (default: 10, max: 20)z-Messages before/after each match (default: 2))r   r   r   r   r   get_recent_observationszgGet the most recent observations about the peer. Useful for understanding what's been learned recently.z6Maximum number of observations to return (default: 10)booleanzKIf true, only return observations from the current session (default: false)F)r   session_onlyget_most_derived_observationszGet observations that have been reinforced most frequently across conversations. These represent the most established facts about the peer.r   get_session_summaryzhGet the session summary (short or long form). Useful for understanding the overall conversation context.summary_typeshortlongz,Type of summary to retrieve (default: short)get_peer_cardzgGet the peer card containing known biographical information about the peer (name, age, location, etc.).delete_observationszDelete observations by their IDs. Use the exact ID shown in [id:xxx] format from search results. Example: if observation shows '[id:abc123XYZ]', pass 'abc123XYZ' to delete it.observation_idszTList of observation IDs to delete (use the exact ID from [id:xxx] in search results)finish_consolidationzSignal that consolidation is complete. Call this when you have finished your consolidation work and are ready to stop. You MUST call this tool when done - do not keep exploring indefinitely.summaryzkBrief summary of what was accomplished (peer card updates, observations consolidated, observations deleted)extract_preferencesa  Extract user preferences and standing instructions from conversation history. This tool performs both semantic and text searches for preferences, instructions, and communication style preferences, then returns them for adding to the peer card. Call this FIRST during consolidation.get_reasoning_chaina
  Get the reasoning chain for an observation - traverse the tree to find premises (for deductive) or sources (for inductive), and/or find conclusions derived from this observation. Use this to understand how an observation was derived or what conclusions depend on it.zAThe document ID of the observation to get the reasoning chain forrD   conclusionsbothzu'premises' to get what this observation is based on, 'conclusions' to get what depends on it, 'both' for full contextr   )observation_id	directionr   )r   r   TOOLSDIALECTIC_TOOLSDIALECTIC_TOOLS_MINIMALDREAMER_TOOLSDEDUCTION_SPECIALIST_TOOLSINDUCTION_SPECIALIST_TOOLSsession_namemessage_created_atrun_idparent_categoryc	                   K   | s,t                               d           t          dg g           S d | D             }	|	s,t                               d           t          dg g           S t	          d          4 d{V }
t          j        |
|||           d{V  ddd          d{V  n# 1 d{V swxY w Y   d	 |	D             }d}	 t          t          j	        j
        |||
          5  t          j        |           d{V }ddd           n# 1 swxY w Y   t          t          t          t!          |	                    |d                    }n2# t"          $ r%}t                               d|           Y d}~nd}~ww xY wg }g }t%          |	          D ]\  }}|	||         }n	 t          t          j	        j
        |||
          5  t          j        |j                   d{V }ddd           n# 1 swxY w Y   nl# t"          $ r_}t                               d|j        |           |                    t/          |j        dd         d|                      Y d}~d}~ww xY wt1          j        |||j        dv r|j        nd|j        dk    r|j        nd|j        dv r|j        nd|j        dk    r|j        nd|j        dk    r	|j        pdnd          }t1          j        |j        ||j        |||j        dv r|j        nd          }|                    |           g }|rt	          d          4 d{V }
t          j         |
||||d           d{V }ddd          d{V  n# 1 d{V swxY w Y   t                               dt!          |          |||           t          t!          |          d |D             |          S )ap  
    Create multiple observations (documents) in the memory system in a single call.

    Uses short-lived DB sessions to avoid holding connections during embedding API calls.

    Args:
        observations: List of validated observation inputs
        observer: The peer making the observation
        observed: The peer being observed
        session_name: Session identifier
        workspace_name: Workspace identifier
        message_ids: List of message IDs these observations are based on
        message_created_at: Timestamp of the message that triggered these observations
        run_id: Agent run id, threaded onto the embedding-call ContextVar so
            EmbeddingCallCompletedEvents emitted here can be joined back to
            the originating agent run.

    Returns:
        ObservationsCreatedResult with created count and any per-observation failures
    z*create_observations called with empty listr   )r}   r~   r   c                 ^    g | ]*}|j                                         t          |          +S rH   )r#   r&   r(   .0r    s     r'   
<listcomp>z'create_observations.<locals>.<listcomp>N  sD       ;%c**  r)   z#No non-empty observations to createzcreate_observations.collectionNrg   rh   c                     g | ]	}|j         
S rH   )r#   r   s     r'   r   z'create_observations.<locals>.<listcomp>a  s    ??????r)   rf   r   r   Tstrictz]Batch embedding failed for create_observations; falling back to per-observation embedding: %sz6Error embedding observation content for level '%s': %s2   zEmbedding failed: rs   rt   )r0   r1   r2   r0   )r1   r2   r1   r@   )r   r   rC   rD   rE   rF   rG   )r#   r   rB   r   	embeddingrC   zcreate_observations.save)	documentsrf   rg   rh   deduplicatez#Created %d observations in %s/%s/%sc                     g | ]	}|j         
S rH   )rB   )r   docs     r'   r   z'create_observations.<locals>.<listcomp>  s    666c	666r)   )!loggerwarningr|   infor   r   get_or_create_collectionr   r   CREATE_OBSERVATIONSr]   r   simple_batch_embeddictzipranger   	Exception	enumerateembedr#   rB   appendrr   r   DocumentMetadatarC   rD   rE   rF   rG   DocumentCreatecreate_documents)r   rg   rh   r   rf   r   r   r   r   normalized_observationsdbcontentsembeddings_by_index
embeddingser   r   ir    r   r   r   accepteds                          r'   r   r   +  s     >  XCDDD(qTVWWWW   
 # X9:::(qTVWWWW :;; 
 
 
 
 
 
 
r+	
 
 
 	
 	
 	
 	
 	
 	
 	

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 @?'>???H9=
# 4:)+	
 
 
 	M 	M  0B8LLLLLLLLJ	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M #c12233ZMMM
 
  
 
 
k	
 	
 	
 	
 	
 	
 	
 	

 /1I')F344 6 63*+A.II+(<B#1!$3	   J J '7&<S[&I&I I I I I I IIJ J J J J J J J J J J J J J J    LI  
 &(+CRC(86166      +#1yGGG ~~%(Y+%=%=S\\4y::: KK-0Y+-E-E))4yK'' 2(
 
 
  $K%)yGGG ~~	
 	
 	
 	 .0H 
899 	 	 	 	 	 	 	R!2#-!!         H	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	1MM	
 	
 	
 %(mm66X666   s    B11
B;>B;"E 3DE DE !D"<E 
F)F		F6"H H8HH	HH	H
I9AI44I9!N
NN    r  token_limitc                 6  K   |r{t          j        |||d           d{V }|                     |           d{V }|                                                                }t          t          |                    S |rt          t          j	                  
                    t          j	        j        |k              
                    t          j	        j        |k                                  t          j	        j                                                                      d          }|                     |           d{V }t          |                                                                          }t          t          |                    S g S )aU  
    Retrieve recent conversation history.

    If session_name is provided, retrieves messages from that session.
    If session_name is None but observed is provided, retrieves recent messages
    sent by the observed peer across all their sessions.

    Args:
        db: Database session
        workspace_name: Workspace identifier
        session_name: Session identifier (optional)
        observed: Peer name to filter by when no session specified (optional)
        token_limit: Maximum tokens to retrieve (default: 8192)

    Returns:
        List of messages in chronological order
    T)rf   r   r  reverseNr   )r   get_messagesexecutescalarsallr   reversedr	   r   Messagewhererf   	peer_nameorder_by
created_atr   r   )	r  rf   r   rh   r  messages_stmtresultmessagesstmts	            r'   r   r     s     0  "/)%#	
 
 
 
 
 
 
 
 
 zz-00000000>>##''))HX&&'''	  6>""U6>0NBCCU6>+x788Xfn/446677U2YY 	 zz$''''''''((,,..//HX&&''' 	r)   levelsr   c           
         K   d}|rdd|ii}t          j        d| ||||||           d{V }t          j        |          S )u  
    Search for observations in memory using semantic similarity.

    Does not require a DB session — ``query_documents`` manages its own
    short-lived sessions so no connection is held during external calls.

    Args:
        workspace_name: Workspace identifier
        observer: The peer who made the observations
        observed: The peer who was observed
        query: Search query text
        limit: Maximum number of results
        levels: Optional list of observation levels to filter by
                (e.g., ["explicit"], ["deductive", "inductive", "contradiction"])
        embedding: Optional pre-computed embedding to avoid redundant API calls

    Returns:
        Representation object containing relevant observations
    NrB   in)r  rf   rg   rh   r   r   filtersr   )r   query_documentsr   from_documents)	rf   rg   rh   r   r   r   r   r#  r   s	            r'   r   r      s      : &*G ,T6N+*%	 	 	 	 	 	 	 	 	I (333r)   c                   K   |sg S d}|r|sddl m}  || ||           d{V }|sg S t          t          j        j                                      t          j        j        |k                                  t          j        j        	                    |                    }|r)|                    t          j        j
        |k              }n9|7|                    t          j        j
        	                    |                    }|                    d          }t          t          j                                      t          j        j        |k                                  t          |j        j                                      |j        j        t          j        j        z
                      dd                                                                                  t          j        j                                                  }|r)|                    t          j        j
        |k              }n9|7|                    t          j        j
        	                    |                    }|                     |           d{V }	t%          |	                                                                          }
|
S )a  
    Retrieve messages for given message IDs along with surrounding context.

    Takes message IDs (from an observation's message_ids field) and retrieves those
    messages plus the messages immediately before and after each one to provide
    conversation context.

    Args:
        db: Database session
        workspace_name: Workspace identifier
        session_name: Session identifier (optional)
        message_ids: List of message IDs to retrieve
        observer: When provided and session_name is None, scope results
            to sessions this peer belongs to

    Returns:
        List of messages in chronological order, including the requested messages and surrounding context
    Nr   )get_peer_session_namestarget_seqsrN   )src.crud.messager'  r	   r   r  seq_in_sessionr  rf   	public_idin_r   ctecbetweenexistsr  r   r  r   r  r  )r  rf   r   r   rg   allowed_session_namesr'  r  target_seqs_cter  r  s              r'   r   r   /  sz     2  	 /3  ;;;;;;&<&<'
 '
 !
 !
 !
 !
 !
 !
 % 	I 	v~,--	v~,>	?	?	v~'++K88	9	9 	  Rzz&.5EFF		*zz&.599:OPPQQhh}--O
 	v~	v~,>	?	?	?$344U#%4v~7TT'"a.. 
 VXX

 

 
&./3355	6	6 	  Rzz&.5EFF		*zz&.599:OPPQQ::d########FFNN$$((**++HOr)   c                   K   g }t                      }g d}d}	 t          j        |           d{V }t          t	          ||d                    }n2# t
          $ r%}	t                              d|	           Y d}	~	nd}	~	ww xY w|D ]}
	 t          j	        | ||
dd||
                    |
          nd|           d{V }|D ]\  }}|D ]w}|j        |k    rj|j        dd	                                         }||vrE|                    |           |                    d
|j                                         d
           x# t
          $ r&}	t                              d|
|	           Y d}	~	d}	~	ww xY wg g |dd         dS )ah  
    Extract user preferences and standing instructions from conversation history.

    Uses semantic search to find messages that might contain preferences or instructions.
    This is language-agnostic and doesn't rely on keyword matching.

    Args:
        workspace_name: Workspace identifier
        session_name: Session identifier (optional)
        observed: The peer whose preferences to extract
        observer: When provided and session_name is None, scope results
            to sessions this peer belongs to

    Returns:
        Dict with 'messages' list containing potentially relevant messages
    )z(user preferences and communication stylez)standing instructions and rules to followz"how user wants responses formattedz!user requirements and constraintsz"things user wants or does not wantNTr   zjBatch embedding failed for extract_preferences; falling back to per-query embedding in search_messages: %sr   r   rf   r   r   r   r   r   rg   d   'z%Error in semantic search for '%s': %s   )instructionspreferencesr  )setr   r   r   r   r   r   r   r   r   rk   r  r#   loweraddr  r&   )rf   r   rh   rg   r  seen_contentsemantic_queriesquery_embeddings_by_queryquery_embeddingsr  r   snippetsmatches_msgcontent_keys                   r'   r   r     so     , H UUL   @D	
!1!DEU!V!VVVVVVV$( "24@@@%
 %
!!  
 
 
x	
 	
 	
 	
 	
 	
 	
 	

 " N N	N!1-)  1< .11%888!        H ' H H
" H HC}00&)k$3$&7&=&=&?&?&l::(,,[999$OO,F0A0A0C0C,F,F,FGGGHH  	N 	N 	NNNBE1MMMMMMMM	N SbSM  s0   9A 
BA>>BB:E
E6E11E6c                       e Zd ZU dZeed<   eed<   eed<   edz  ed<   eej                 dz  ed<   e	ed<   e
ed	<   ej        ed
<   dZedz  ed<   dZedz  ed<   dZedz  ed<   dZedz  ed<   dS )ToolContextz'Context object passed to tool handlers.rf   rg   rh   Nr   current_messagesinclude_observation_idshistory_token_limitdb_lockconfigurationr   
agent_typer   )ru   rv   rw   rx   ry   rz   r   r   r  boolr`   rl   rm   rM  r   r   rN  r   rH   r)   r'   rH  rH    s         11MMMMMM*6>*T1111!!!! \26M(4/666FC$J!Jd
!!!"&OS4Z&&&&&r)   rH  forced_levelctx
tool_inputrQ  c                  K   |                     dg           }|sdS | j        rdnd}|D ] }|||d<   
|                    d|           !g }g }|D ]}	 t          j                            |          }ng# t          $ rZ}	|                    t          t          |                     dd                    dd	         d
|	                      Y d}	~	d}	~	ww xY w| j        rF|j
        dk    r;|                    t          |j        dd	         d|j
         d                     |                    |           |s$d                    d |D                       }
d|
 S | j        r1d | j        D             }t          | j        d         j                  }ng }t                      }| j        4 d{V  t!          || j        | j        | j        | j        ||| j        | j        	  	         d{V }ddd          d{V  n# 1 d{V swxY w Y   ||j        z   }|j        }|                    d          }|                    d          }|                    d          }|                    d          }| j        rb| j        r[| j        rTt7          t9          | j        t;                      | j        | j        | j        | j        | j        |j        |	  	                   d|j         d| j         d| j         d| d| d| d| d}|r7d                    d |D                       }
|d t?          |           d!|
 z  }d"d#l m!}  |||j        |d$%          S )&z Handle create_observations tool.r   z!ERROR: observations list is emptyr/   r0   NrB   r#   r   r   zValidation failed: r   z6Deriver can only create 'explicit' observations, got 'r7  z; c              3   :   K   | ]}d |j          d|j         V  dS r7  z': Nr   r   fs     r'   	<genexpr>z3_handle_create_observations_impl.<locals>.<genexpr>  I       $
 $
45/!//ag//$
 $
 $
 $
 $
 $
r)   z+ERROR: All observations failed validation: c                     g | ]	}|j         
S rH   )idr   rE  s     r'   r   z4_handle_create_observations_impl.<locals>.<listcomp>  s    >>>#sv>>>r)   r)  )	r   rg   rh   r   rf   r   r   r   r   r1   r2   	r   	iterationr   rN  rf   rg   rh   conclusion_countr   zCreated z observations for  by  (z explicit, z deductive, z inductive, z contradiction)c              3   :   K   | ]}d |j          d|j         V  dS rV  r   rW  s     r'   rY  z3_handle_create_observations_impl.<locals>.<genexpr>Q  rZ  r)   z
Failed : r   r   )r}   r   r   )"rk   rI  
setdefaultr   ObservationInputmodel_validater   r  rr   ry   rB   r#   joinr  r   rL  r   rg   rh   r   rf   r   r   r   r~   countrN  r   r   r   r}   r   src.utils.typesr   )rR  rS  rQ  raw_observationsdefault_levelr    r   validation_failures	validatedr  failure_detailsr   r   r  all_failuresr   explicit_countdeductive_countinductive_countcontradiction_countresponser   s                         r'    _handle_create_observations_implrw    sI      "~~nb99 322 #&"6GJJKM 3 3#'CLLNN7M2222 46L46 ' '		0??DDII 	 	 	&&"$'	2(>(>$?$?$D333     HHHH	  	IOz$A$A&&"$-$5crc$:eS\Sbeee     I&&&& O)) $
 $
9L$
 $
 $
 
 
 O_NNN  +>>)=>>> !5b!9!DEE(]] { 
 
 
 
 
 
 
 
*%\\)-#1:/

 

 

 

 

 

 

 

 


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 '6L "F\\*--Nll;//Oll;//O ,,77 z 
cn 
)< 
,z/11 # 3>"1!'!5
 
 
	
 	
 	
	M6' 	M 	M3< 	M 	MS\ 	M 	M	M 	M'6	M 	M	M 	M(;	M 	M 	M   G)) $
 $
9E$
 $
 $
 
 
 	FL 1 1FF_FFF +*****:#)#76JJ   s+   A44
C>ACC9=H
HHc                 2   K   t          | |           d {V S Nrw  rR  rS  s     r'   _handle_create_observationsr|  b  s*       2#zBBBBBBBBBr)   c                 6   K   t          | |d           d {V S )Nr0   rP  rz  r{  s     r'   %_handle_create_observations_deductiver~  h  F       2          r)   c                 6   K   t          | |d           d {V S )Nr1   rP  rz  r{  s     r'   %_handle_create_observations_inductiver  r  r  r)   c                   K   | j         4| j         j        j        s#t                              d| j                   	 dS |                    d          }|"t                              d| j                   dS g }t                      }t          |t                    r t          t          t                   |          nt          |          g}|D ]}t          |                                          }|s&d                    |                                                                          }||v rd|                    |           |                    |           |s"t                              d| j                   d	S t'          |          t(          k    rCt                              d
t(          t'          |          t(                     |dt(                   }| j        4 d{V  t-          d          4 d{V }	t/          j        |	| j        || j        | j                   d{V  ddd          d{V  n# 1 d{V swxY w Y   ddd          d{V  n# 1 d{V swxY w Y   t                              d| j         d| j         d| j                    | j        ri| j        rb| j        r[t=          t?          | j        tA                      | j        | j        | j        | j        | j        t'          |                               ddl!m"}
  |
d| j         d| j         dt'          |          d          S )zHandle update_peer_card tool.Nz3Peer card creation disabled for %s, skipping updatezHPeer card creation is disabled for this workspace/session configuration.r#   zGPeer card update called with None content for %s, keeping existing cardz1Peer card content was empty, no update performed. zBPeer card update normalized to empty for %s, keeping existing cardzEPeer card content was empty after normalization, no update performed.zBPeer card update exceeded max facts (%s), truncating from %s to %sztool.update_peer_card)rf   	peer_cardrg   rh   zUpdated peer card for /)r   r_  r   rN  rf   rg   rh   facts_countr   re  ra  T)peer_card_updatedr  r   )#rM  r  creater   r   rf   rk   r   r;  
isinstancer   r   ry   r&   ri  r<  splitr=  r  r   MAX_PEER_CARD_FACTSrL  r   r   set_peer_cardrg   rh   r   rN  r   r   r   r   rk  r   )rR  rS  raw_peer_card_contentnormalized_peer_cardseenr7   itemlinenormalized_keyr  r   s              r'   _handle_update_peer_cardr  |  s     
 $S->-H-O$A	
 	
 	

 W	
 	
 'NN955 $U	
 	
 	
 CB ')UUD +T22	*T#Y-...'(() 

  
* 
*4yy   	 $**,,"4"4"6"677T!!   ##D))))   WP	
 	
 	
 WV
  #666P$%%		
 	
 	
  44H5H4HI{ 
 
 
 
 
 
 
 
J'>?? 
 
 
 
 
 
 
2 -*\\
 
 
 	
 	
 	
 	
 	
 	
 	

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 KKS!3SSclSSS\SS  
 z 
cn 
)< 
)z/11 # 3>"1 455	 	 		
 	
 	
 +*****:III3<II'+C@T<U<UVV   s6   )I#?/I .I# 
I
	
I#I
	I##
I-0I-c                   K   |}t          d          4 d{V }t          || j        | j        | j        | j                   d{V }|s	 ddd          d{V  dS d                    d |D                       }ddd          d{V  n# 1 d{V swxY w Y   | j        r
d| j         n
d| j         d	}d
t          |           d| d| }t          |          S )zHandle get_recent_history tool.ztool.get_recent_historyN)rf   r   rh   r  z!No conversation history available
c                 J    g | ] }|j          d t          |j                   !S )rd  )r  r   r#   r   ms     r'   r   z._handle_get_recent_history.<locals>.<listcomp>  s3    WWW!EE8CCEEWWWr)   zfrom session zfrom z across sessionszConversation history (z
 messages ):
)	r   r   rf   r   rh   rK  ri  r   r   )rR  rS  rD  r  historyhistory_textscoper   s           r'   _handle_get_recent_historyr    s      	A344 
 
 
 
 
 
 
.@-)\//
 /
 /
 )
 )
 )
 )
 )
 )
  	76
 
 
 
 
 
 
 
 
 
 
 
 
 
 yyWWwWWW
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 	4*(***3S\333 

 Xc'llWWeWWWWF"6***s   2BB
BBc           	        K   ddl m} t          t          |                    d          d          d          }|d         }	 t          t          j        j        | j	        | j
        | j                  5  t          j        |           d{V }ddd           n# 1 swxY w Y   n'# t          $ r d	t          j        j         d
z   cY S w xY w|ddt%          |          d}t'          j        d| j	        | j        | j        |||           d{V }t/          j        |          }|                                }	|	dk    ri |ddi}
| j        dk    rt          t          |                    d          d          d          }d}t'          j        | j	        | j        ||d|| j                   d{V }|rt;          |d| d          }|r%i |
dt3          |          i} |d| |          S  |d| d|
          S  |d| d|
          S | j        r|                                ntA          |          }|	|d<    |d|	 d| d| |          S )zHandle search_memory tool.r   re  r   r   r   r   r   Nz,ERROR: Query exceeds maximum token limit of z. Please use a shorter query.TrN   )r   used_embeddingembedding_query_countquery_tokens)r  rf   rg   rh   r   r   r   results_count	dialecticr5  for query 'r7  z.No observations yet. Message search results:

r   z!No observations found for query 'zb', and no messages found in history. Try a different phrasing or use grep_messages for exact text.Found z observations for query 'z':

)!rk  r   r   rd   rk   r   r   SEARCH_MEMORYr]   rf   r   r   r   r  rb   r   	EMBEDDINGMAX_INPUT_TOKENS_estimate_tokens_safer   r$  rg   rh   r   r%  r   rN  r   r   _format_message_snippetsrJ  str_with_idsry   )rR  rS  r   r   r   query_embeddingsearch_metar   memtotal_countzero_hit_metar   message_outputrB  fallback_metamem_strs                   r'   _handle_search_memoryr    s      +*****	*..11266;;EwE
# .4-:/	
 
 
 	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  
 
 
:#4SSST	
 	
 	

 !"-e44	# #K *)!        I 
'	
2
2C''))Ka <;;;;>[((	*.."9"92>>CCE!N!1"1 - )        H  !94E444" "   Q= Q/3x== Q Q!z_~__*    :] ] ] ] '    z@@@@"
 
 
 	
 %($?Mc   SXXG#.K :UUUuUUGUU   s6   1B' 4BB' BB' "B#B' '!C
Cc                   K   t          d          4 d{V }t          || j        | j        |d         | j                   d{V }|sd|d          cddd          d{V  S d                    d |D                       }ddd          d{V  n# 1 d{V swxY w Y   dt          |           d	| }t          |          S )
z$Handle get_observation_context tool.ztool.get_observation_contextNr   )rf   r   r   rg   zNo messages found for IDs r  c                 h    g | ]/}t          t          |j                  |j        |j                  0S rH   r   r   r#   r  r  r  s     r'   r   z3_handle_get_observation_context.<locals>.<listcomp>c  sK         /-ai88LK   r)   z
Retrieved z messages with context:
)r   r   rf   r   rg   ri  r   r   )rR  rS  r  r  messages_textr   s         r'   _handle_get_observation_contextr  T  s      899 
 
 
 
 
 
 
R0-)"=1\
 
 
 
 
 
 
 
 
  	LK
=0IKK
 
 
 
 
 
 
 
 
 
 
 
 
 
 		  "  	
 	

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
( R#h--QQ-QQF"6***s   <B'B
B"%B"c           	      V  K   ddl m} |d         }t          t          |                    d          d          d          }t          t          j        j        | j	        | j
        | j                  5  t          j        |           d{V }ddd           n# 1 swxY w Y   t          j        | j	        | j        ||d	|| j        
           d{V }|ddt%          |          t'          |          d}|s |d| d|          S t)          |d| d          } |||          S )zHandle search_messages tool.r   re  r   r   r   r   r   NrS   r5  TrN   r   r  r  r  r  No messages found for query 'r7  r   r  )rk  r   r   rd   rk   r   r   SEARCH_MESSAGESr]   rf   r   r   r   r  r   r   r   rg   r  r   r  )	rR  rS  r   r   r   r  rB  r  	formatteds	            r'   _handle_search_messagesr  p  s      +*****wE	*..11266;;E 
 ,2)z+	
 
 
 > > !1 6u = =======> > > > > > > > > > > > > > > ))%!        H !"-e44X# #K  
z<E<<< 
 
 
 	
 )3I3I3I3IJJI:i+>>>>s   3BB!Bc                   K   |                     dd          }|sdS t          t          |                     d          d          d          }t          t          |                     d          d          d          }t          j        | j        | j        |||| j        	           d
{V }|sd| dS g }t          d |D                       }t          |d          D ]\  }\  }	}
g }|
D ]E}t          |j        |          }|                    t          ||j        |j                             F|
r|
d         j        nd}|                    d| d| dt!          |	           dd                    |          z              d| d| dt!          |           dd                    |          z   }t%          |          S )zHandle grep_messages tool.r   r   z#ERROR: 'text' parameter is requiredr   r   r8  r   rS   )rf   r   r   r   r   rg   NzNo messages found containing 'r7  c              3   :   K   | ]\  }}t          |          V  d S ry  r   r   rC  rD  s      r'   rY  z(_handle_grep_messages.<locals>.<genexpr>  ,      @@!G@@@@@@r)   rN   r   unknown--- Snippet  (session: ,  match(es)) ---
r  r  z messages containing 'z' in z conversation snippets:



)rk   r   rd   r   r   rf   r   rg   sumr   r   r#   r  r   r  r  r   ri  r   )rR  rS  r   r   r   rB  snippet_textstotal_matchesr  rC  contextlinesrE  r   sessr   s                   r'   _handle_grep_messagesr    s;      >>&"%%D 544	*..11266;;E*..!122A66 N ')%%        H  877777  "M@@x@@@@@M!*8Q!7!7 
 
GW 	 	C0dCCILL.y#.#-XX    +2@wqz&&yP1PPPPWPPPii	
 	
 	
 	
 	lkkdkkXkkk
++m
$
$	%  #6***r)   date_str
param_namec                     | sdS 	 t          j        |                     dd                    S # t          $ r d| d|  dcY S w xY w)z?Parse a date string, returning datetime, None, or error string.NZz+00:00zERROR: Invalid z	 format 'z&'. Use ISO format (e.g., '2024-01-15'))r   fromisoformatreplacerb   )r  r  s     r'   _parse_dater    st     tg%h&6&6sH&E&EFFF g g gfffhffffffgs   '. AAc                   K   |                     d          }|                     d          }t          t          |                     d          d          d          }|                     dd          }t          |d          }t	          |t
                    r|S t          |d          }t	          |t
                    r|S t          d          4 d{V }t          j        || j	        | j
        ||||| j        	           d{V }	t          |	          }
|	rd
                    d |	D                       nd}ddd          d{V  n# 1 d{V swxY w Y   g }|r|                    d|            |r|                    d|            |
s|rd                    |          nd}d| S |rd                    |          nd}|dk    rdnd}d|
 d| d| d| }t          |          S )z'Handle get_messages_by_date_range tool.r   r   r   r   r   r   ztool.get_messages_by_date_rangeN)rf   r   r   r   r   r   rg   r  c                 h    g | ]/}t          t          |j                  |j        |j                  0S rH   r  r  s     r'   r   z6_handle_get_messages_by_date_range.<locals>.<listcomp>  sI         31!)<<alAK   r)   r   after before  and zspecified rangezNo messages found zall timer   zoldest firstznewest firstr  z messages (r  z):

)rk   r   rd   r  r  ry   r   r   r   rf   r   rg   r   ri  r  r   )rR  rS  after_date_strbefore_date_strr   r   r   r   r  r  	msg_countr  
date_range
range_desc
order_descr   s                   r'   "_handle_get_messages_by_date_ranger    s       ^^L11N nn]33O	*..11266;;ENN7F++E^\::J*c"" o}==K+s## ;<< 
 
 
 
 
 
 
8-)!#\	
 	
 	
 	
 	
 	
 	
 	
 	
 MM	 	DII  &	      	
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2 J 53>33444 75O55666 11;RW\\*---AR
0J000-7Gj)))ZJ#(E>>~J 	WVVzVVZVV}VV  #6***s   A$E
EEc                   K   |                     dd          }|sdS |                     d          }|                     d          }t          t          |                     d          d          d          }t          t          |                     d          d	          d	          }t          |d          }t	          |t
                    r|S t          |d          }t	          |t
                    r|S t          t          j        j	        | j
        | j        | j        
          5  t          j        |           d{V }	ddd           n# 1 swxY w Y   t          j        | j
        | j        ||||||	| j        	  	         d{V }
g }|r|                    d|            |r|                    d|            |rdd                    |           dnd}|ddt+          |          t-          |
          d}|
st/          d| d| |          S t1          |
d| d|           }t/          ||          S )z%Handle search_messages_temporal tool.r   r   z$ERROR: 'query' parameter is requiredr   r   r   r   r   rS   r   N)	rf   r   r   r   r   r   r   r   rg   r  r  rb  r  )TrN   r  r  r7  r   r  )rk   r   rd   r  r  ry   r   r   r  r]   rf   r   r   r   r  r   r   r   rg   r  ri  r  r   r   r  )rR  rS  r   r  r  r   r   r   r   r  rB  date_filterfilter_descr  r  s                  r'    _handle_search_messages_temporalr    s      NN7B''E 655^^L11N nn]33O	*..11266;;E:>>2B#C#CQGGKKN^\::J*c"" o}==K+s##  
 ,2)z+	
 
 
 > > !1 6u = =======> > > > > > > > > > > > > > > 2)%%!
 
 
 
 
 
 
 
 
H  K 64N44555 86_667777BJ3w||K003333K !"-e44X# #K  
IEIIKII 
 
 
 	

 )3V3V3V3V3VWWIi+>>>>s   (EEEc                 H  K   |                     dd          }t          d          4 d{V }t          j        || j        | j        | j        t          t          |                     d          d          d          |r| j	        nd           d{V }t          j        |          }ddd          d{V  n# 1 d{V swxY w Y   |                                }|d	k    rd
S |rdnd}| j        r|                                nt          |          }d| d| d| S )z$Handle get_recent_observations tool.r   Fztool.get_recent_observationsNr   r   r6  )r  rf   rg   rh   r   r   r   zNo recent observations foundzthis sessionzall sessionsr  z recent observations from :

)rk   r   r   query_documents_recentrf   rg   rh   r   rd   r   r   r%  r   rJ  r  ry   )	rR  rS  r   r  r   representationr  r  repr_strs	            r'   _handle_get_recent_observationsr  T  s      >>.%88L899 	B 	B 	B 	B 	B 	B 	BR5-\\i
w 7 7<<cBB-9C))t
 
 
 
 
 
 
 
 
	 (6yAA	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B !$$&&Ka--*>NNE &	!##%%%   
 RKQQ5QQxQQQs   A<B<<
C	Cc                   K   t          d          4 d{V }t          j        || j        | j        | j        t          t          |                    d          d          d                     d{V }t          j
        |          }ddd          d{V  n# 1 d{V swxY w Y   |                                }|dk    rdS | j        r|                                nt          |          }d	| d
| S )z*Handle get_most_derived_observations tool.z"tool.get_most_derived_observationsNr   r   r6  )r  rf   rg   rh   r   r   z!No established observations foundr  z4 established (frequently reinforced) observations:

)r   r   query_documents_most_derivedrf   rg   rh   r   rd   rk   r   r%  r   rJ  r  ry   )rR  rS  r  r   r  r  r  s          r'   %_handle_get_most_derived_observationsr  o  s      >?? B B B B B B B2;-\\i
w 7 7<<cBB
 
 
 
 
 
 
 
 
	 (6yAAB B B B B B B B B B B B B B B B B B B B B B B B B B B !$$&&Ka22 &	!##%%%   
 bKaaW_aaas   A2B
B&)B&c                   K   | j         sdS |                    dd          }|dk    rt          j        j        nt          j        j        }t          d          4 d{V }t          j        || j        | j         |           d{V }ddd          d{V  n# 1 d{V swxY w Y   |sdS d|d          d	|d
          S )z Handle get_session_summary tool.z'ERROR: No session available for summaryr   r   r   ztool.get_session_summaryNz No session summary available yetzSession summary (r  r#   )	r   rk   r   SummaryTypeLONGSHORTr   get_summaryrf   )rR  rS  r   str  r   s         r'   _handle_get_session_summaryr    s       988>>.'::L 6!! 	###) 
 455 
 
 
 
 
 
 
"."C$4b
 
 
 
 
 
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  211Pw~6PPGI<NPPPs   (B
B#&B#c                 D  K   |}t          d          4 d{V }t          j        || j        | j        | j                   d{V }ddd          d{V  n# 1 d{V swxY w Y   |s
d| j         S d| j         dd                    d |D                       z   S )	zHandle get_peer_card tool.ztool.get_peer_cardN)rf   rg   rh   zNo peer card available for zPeer card for z:
r  c              3       K   | ]	}d | V  
dS z- NrH   )r   facts     r'   rY  z(_handle_get_peer_card.<locals>.<genexpr>  s9       : :T: : : : : :r)   )r   r   r   rf   rg   rh   ri  )rR  rS  rD  r  r  s        r'   _handle_get_peer_cardr    sn     A.// 
 
 
 
 
 
 
2,-\\	
 
 
 
 
 
 
 
 
	
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  <;S\;;;-CL---		 : : ): : : 1 1  s   .A
A$'A$c                   K   |                     dg           }|sdS | j        4 d{V  t          d          4 d{V }t          j        || j        || j        | j                   d{V }ddd          d{V  n# 1 d{V swxY w Y   ddd          d{V  n# 1 d{V swxY w Y   d |D             }|D ]!}||vrt          	                    d|           "t          |          }|dk    rn| j        rg| j        r`| j        rYt          t          | j        t!                      | j        | j        | j        | j        | j        |d	 |D             
	  	                   ddlm}  |d| d|d |D             d          S )z Handle delete_observations tool.r   z$ERROR: observation_ids list is emptyNztool.delete_observations)rf   document_idsrg   rh   c                     h | ]\  }}|S rH   rH   )r   doc_idrD  s      r'   	<setcomp>z._handle_delete_observations.<locals>.<setcomp>  s    333ifa6333r)   zLFailed to delete observation %s (not found, already deleted, or wrong scope)r   c                     g | ]\  }}|S rH   rH   r   rD  rB   s      r'   r   z/_handle_delete_observations.<locals>.<listcomp>  s    666(!U666r)   r^  re  zDeleted z observationsc                     g | ]\  }}|S rH   rH   r  s      r'   r   z/_handle_delete_observations.<locals>.<listcomp>  s    555Eu555r)   )deleted_countr   r   )rk   rL  r   r   delete_documentsrf   rg   rh   r   r   r   r   rN  r   r   r   r   rk  r   )	rR  rS  r   r  deleteddeleted_idsobs_idr  r   s	            r'   _handle_delete_observationsr    s      !nn%6;;O 655{ 
 
 
 
 
 
 
 
J'ABB 
 
 
 
 
 
 
b--(\\
 
 
 
 
 
 
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 437333K!  $$NN^  
 LLMqSZCNs?R,z/11 # 3>"1!.66g666
 
 
	
 	
 	
 +*****:7=777*55W555
 
   s5   B$ /B/B$
B	B$B	B$$
B.1B.c                 @   K   | }|                     dd          }d| S )z!Handle finish_consolidation tool.r   zConsolidation completezCONSOLIDATION_COMPLETE: )rk   )rR  rS  rD  r   s       r'   _handle_finish_consolidationr    s/       	AnnY(@AAG/g///r)   c                   K   |}t          t          j        j        | j        | j        | j                  5  t          | j        | j        | j	        | j
                   d{V }ddd           n# 1 swxY w Y   |                    dg           }|sdS dt          |           dd                    d	 |D                       d
g}d                    |          S )z Handle extract_preferences tool.r   )rf   r   rh   rg   Nr  zYNo potentially relevant preference or instruction messages found in conversation history.z!**Potentially Relevant Messages (z):**r  c              3       K   | ]	}d | V  
dS r  rH   r]  s     r'   rY  z._handle_extract_preferences.<locals>.<genexpr>  s(      11*s**111111r)   a  
**Action Required:** Review these messages and extract any preferences or standing instructions to add to the peer card using `update_peer_card`. Summarize as clear rules (e.g., 'INSTRUCTION: Always include cultural context') or preferences (e.g., 'PREFERENCE: Brief responses').r  )r   r   PREFERENCE_EXTRACTIONr]   rf   r   r   r   r   rh   rg   rk   r   ri  )rR  rS  rD  resultsr  output_partss         r'   _handle_extract_preferencesr    sW      	A 
 28)z+	
 
 
 
 
 ,-)\\	
 
 
 
 
 
 
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 {{:r**H kjj 	@CMM???		1111111	RL ;;|$$$s   .A00A47A4rB  c                 *   g }t          d | D                       }t          | d          D ]\  }\  }}g }|D ]D}t          |j                  }	|                    t          |	|j        |j                             E|r|d         j        nd}
|                    d| d|
 dt          |           dd	
                    |          z              d
| dt          |            d| dd
                    |          z   }t          |          d         S )a  Format message snippets for output.

    Returns bare `str` because callers concatenate it into other strings
    or place it into `ToolResult.content`. Callers that need the
    truncation telemetry signal route their own output through
    `_maybe_truncated_result` themselves.
    c              3   :   K   | ]\  }}t          |          V  d S ry  r  r  s      r'   rY  z+_format_message_snippets.<locals>.<genexpr>  r  r)   rN   r   r  r  r  r  r  r  r  z matching messages in z conversation snippets r  r  )r  r   r   r#   r  r   r  r  r   r   ri  r   )rB  r   r  r  r  rC  r  r  rE  r   r  r   s               r'   r  r    s\     "M@@x@@@@@M!*8Q!7!7 
 
GW 	 	C1#+>>ILL.y#.#-XX    +2@wqz&&yP1PPPPWPPPii	
 	
 	
 	
 	hggc(mmgg\`ggg
++m
$
$	%  !((++r)   c           
      V  K   |                     d          }|sdS |                     dd          }|dvrd| dS t          d          4 d	{V }t          j        || j        |g           d	{V }|r|d
         sd| dcd	d	d	          d	{V  S |d
         }g }|j        pd}|                    d|j         d| d|j                    |dv r|dk    r|j	        rt          j        || j        |j	                   d	{V }	|	rvg }
|	D ]3}|j        pd}|
                    d|j         d| d|j                    4|                    dt          |	           dd                    |
          z              n4|                    dt          |j	                   d           n|dk    r|j	        rt          j        || j        |j	                   d	{V }|rug }|D ]3}|j        pd}|                    d|j         d| d|j                    4|                    dt          |           dd                    |          z              n]|                    dt          |j	                   d           n1|dk    r|                    d           n|                    d           |dv rt          j        || j        || j        | j                    d	{V }|rug }|D ]3}|j        pd}|                    d|j         d| d|j                    4|                    d!t          |           dd                    |          z              n|                    d"           d	d	d	          d	{V  n# 1 d	{V swxY w Y   d                    |          S )#z Handle get_reasoning_chain tool.r   z#ERROR: 'observation_id' is requiredr   r   r   zERROR: Invalid direction 'z/'. Must be 'premises', 'conclusions', or 'both'ztool.get_reasoning_chainNr   zERROR: Observation 'z' not foundr/   z**Observation [id:z] (z):**
)rD   r   r0   z - [id:z): z
**Premises (r  z
**Premises:** Referenced z' premise IDs but none found in databaser1   z
**Sources (z
**Sources:** Referenced z& source IDs but none found in databasezC
**Premises/Sources:** N/A (explicit observations have no premises)z$
**Premises/Sources:** None recorded)r   r   r   z
**Derived Conclusions (z$
**Derived Conclusions:** None found)rk   r   r   get_documents_by_idsrf   rB   r  r\  r#   rC   r   ri  get_child_observationsrg   rh   )rR  rS  r   r   r  docsr   r  rB   rD   premise_linespp_levelrE   source_linesss_levelchildrenchild_linesr/  c_levels                        r'   _handle_get_reasoning_chainr$  1  s*       ^^$455N 544{F33I;;;fIffff 455 JM JM JM JM JM JM JM.r33EGWXXXXXXXX 	F47 	FE.EEEJM JM JM JM JM JM JM JM JM JM JM JM JM JM
 Q"$ 	'ZVVVEVVVVWWW ,,,###!%!:*CN" "        /1M% Y Y"#'"7Z%,,-Wqt-W-W-W-WAI-W-WXXXX ''>X>>>))M223   
 !''rc#.6I6Irrr    +%%#.% $ 9*CN! !        .0L$ X X"#'"7Z$++,Vad,V,Vw,V,V19,V,VWWWW ''<G<<<tyy?V?VV    !''pS5H5Hppp    *$$##Z    ##$KLLL ///!8"        H  
M)+! S SAg3G&&'Q'Q'Q''Q'Qai'Q'QRRRR##EHEEEii,,-   
 ##$KLLLUJM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JM JMX 99\"""s   2NKN
NN_TOOL_HANDLERSrI  rJ  rK  rM  rN  c                    K   t          | ||           d{V }t          | ||||||||||	|
          dt          dt          t          t          f         dt          ffd}|S )a  
    Create a unified tool executor function for all agent operations.

    This factory function captures the agent's context and returns an async callable
    that can execute any tool from AGENT_TOOLS or DIALECTIC_AGENT_TOOLS.

    Each tool handler manages its own short-lived DB sessions via tracked_db(),
    so no long-lived database session is needed.

    Args:
        workspace_name: Workspace identifier
        observer: The peer making observations/queries
        observed: The peer being observed/queried about
        session_name: Session identifier (optional for global queries)
        current_messages: List of current messages being processed (optional, for deriver)
        include_observation_ids: If True, include observation IDs in output (for dreamer agent)
        history_token_limit: Maximum tokens for get_recent_history (default: 8192)
        configuration: Resolved configuration for checking feature flags (optional)
        run_id: Optional run ID for telemetry correlation
        agent_type: Optional agent type for telemetry (dialectic, deriver, dreamer)
        parent_category: Optional parent category for CloudEvents

    Returns:
        An async callable that executes tools with the captured context
    N)rf   rg   rh   r   rI  rJ  rK  rL  rM  r   rN  r   	tool_namerS  r!   c                 \  K   ddl }ddlm}m}m}m}m} t                              d| t          |
                                                     |                                }d}	i }
d}	 t                              |           }|r} ||           d{V }t          ||          r|j        }	|j        }
n|}	t                              d| t#          |	          t          |

                                                     n!d|  }	d	}t                              |	           n# t&          j        $ r
 d
|  d}	d	} t*          $ r.}d
|  d| }	d	}t                              |	           Y d}~nd}~wt,          $ r.}d
|  d| }	d	}t                              |	           Y d}~nUd}~wt.          $ rE}d
|  dt1          |          j         d| }	d	}t                              |	d	           Y d}~nd}~ww xY w|                                |z
  dz  } ||
           t7          | ||	|
| |             |             |            	  	         nZ# |                                |z
  dz  } ||
           t7          | ||	|
| |             |             |            	  	         w xY w|	S )z
        Execute a tool and return result for LLM.

        Args:
            tool_name: Name of the tool to execute
            tool_input: Tool input arguments

        Returns:
            String result describing what was done
        r   N)r   r   !get_current_provider_tool_call_idget_current_tool_call_seqset_last_tool_metadataz[tool call] %s keys=%sr   Fz([tool result] %s len=%d metadata_keys=%szUnknown tool: TzTool z
 cancelledz failed with invalid input: z missing required parameter: z failed unexpectedly: rd  exc_infoi  )	rR  r'  duration_ms
result_strr   is_errorr_  tool_call_seqprovider_tool_call_id)timerk  r   r   r)  r*  r+  r   r   sortedkeysperf_counterr%  rk   r  r#   r   r   r   rl   CancelledErrorrb   KeyErrorr   r-   ru   rt   _emit_agent_tool_call_completed)r'  rS  r3  r   r   r)  r*  r+  r   r/  r   r0  handlerhandler_resultr  r.  rR  s                   r'   execute_toolz*create_tool_executor.<locals>.execute_tool  s      		
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	,i
@Q@Q9R9RSSS!!## 
#%L	$((33G +'.wsJ'?'?!?!?!?!?!?!? nj99 0!/!7J-6HH!/J
 >
OO8==??++	    :i99
z***% 	 	 	 7666JH 	' 	' 	'KKKKKJHNN:&&&&&&&& 	' 	' 	'LLLLLJHNN:&&&&&&&& 	4 	4 	4 Q	PPa9IPPQPP  HLLdL33333333	4  ,,..6$>K
 #"8,,,+#'%!!//117799&G&G&I&I
 
 
 
 
  ,,..6$>K
 #"8,,,+#'%!!//117799&G&G&I&I
 
 
 
 
 sV   ,B:D' &I '!G9$E1,I 1G9>$F'"I 'G94;G4/I 4G99I AJ))rp   rH  ry   r   r   )rf   rg   rh   r   rI  rJ  rK  rM  r   rN  r   shared_lockr<  rR  s                @r'   create_tool_executorr>    s      P -^XxPPPPPPPPK
%!) 7/#'  Cpc ptCH~ p# p p p p p pd r)   r'  r.  r/  r   r0  r_  r1  r2  c        	            | j         r| j        r| j        sdS 	 ddlm}	m}
  |
 |	di d| j         d|d|d|d| j        d	| j        d
| j        d|d|d|dt          |          d|                    d          dt          |          dt          |                    dd                    d|                    d          d|                    d          d|                    d          d|                    d          dt          |                    d          pd                     dS # t          $ r  t                              dd           Y dS w xY w)u   Build and emit AgentToolCallCompletedEvent. Best-effort; swallows errors.

    Skipped when the executor was constructed without agent identifiers
    (run_id / agent_type / parent_category) — telemetry attribution requires
    all three.
    Nr   )AgentToolCallCompletedEventr   r   r_  r1  r2  r   rN  rf   r'  r.  r0  result_charsr   result_tokens_estimater   Fr  r   r  r  r  z*Failed to emit AgentToolCallCompletedEventTr,  rH   )r   rN  r   src.telemetry.eventsr@  r   rf   r   rk   _estimate_tokensrO  r`   r   r   debug)rR  r'  r.  r/  r   r0  r_  r1  r2  r@  r   s              r'   r9  r9  S	  s0   $ J 3> c.A RJJJJJJJJ''   zz#) ,m '<&;	
 !$ 3 3 >>  #11 $) (K " !___ 08||40 0 0 (8
'C'C'C  #8<<#G#GHHH!" &\\.999#$ ll7+++%& 'll?;;;'(  (||,<===)* '*(,,7N*O*O*TST&U&U&U+	
 	
 	
 	
 	
2  R R RADQQQQQQRs   D D; ;&E%$E%c                     | sdS 	 ddl }|                    d          }t          |                    |                     S # t          $ r# t          dt          |           dz            cY S w xY w)z?Tiktoken-based size proxy for tool result strings. Best-effort.r   Ncl100k_baserN      )tiktokenget_encodingr   encoder   r   )r   rI  encodings      r'   rD  rD  	  s     q	& ((778??4(())) & & &1c$ii1n%%%%%&s   :A *A.-A.c                 (    | sdS t          |           S )zWrapper around `_estimate_tokens` that returns None on falsy input.

    Used by search-handler metadata where we want `query_tokens=None`
    when the query is empty rather than 0 (which could be confused with a
    real measurement).
    N)rD  )r   s    r'   r  r  	  s      tD!!!r)   ry  )NN)Nr  )NNFr  NNNN)vrl   loggingweakrefcollections.abcr   dataclassesr   r   typingr   r   pydanticr   
sqlalchemyr	   sqlalchemy.ext.asyncior
   srcr   r   r   
src.configr   src.dependenciesr   src.embedding_clientr   
src.modelsr   src.schemasr   rC  r   r   r   r   r   	src.utilsr   src.utils.formattingr   r   src.utils.representationr   rk  r   r   r   	getLoggerru   r   r  rg  r(   r   ry   rI   rV   rZ   r\   r`   rd   WeakValueDictionaryre   tuplerm   rz   rj   rp   rr   r|   rO  r   r   r   r   r   r   r   r   r   r   r   r   r  r   floatr   r   r   rH  rw  r|  r~  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r$  r%  r>  r9  rD  r  rH   r)   r'   <module>rc     s      $ $ $ $ $ $ ! ! ! ! ! !               $ $ $ $ $ $       / / / / / / % % % % % % % % % %       ' ' ' ' ' ' 1 1 1 1 1 1       - - - - - -              !           L L L L L L L L 3 3 3 3 3 3 U U U U U U U U U U		8	$	$  C		!CC C C C:d38n : : : :zC$sCx. C C C CLDcN    4'DcN ' ' ' 'T	S 	3 	3 	 	 	 	*  G!! G/c3m0Dgl0RS    #&25\   >         % % % % % % % % *.+ ++$J+
3T>+ + + +.C ,>    (' 's 'sTz 'S ' ' ' ' 9=*( *(*(*(+.:*(*( *( *( *(ZF$% g##C==??! ! ((

 

 F$  $/ m##Q??AA! ! ((

 

& &!F$> $/ v##Q??AA! ! ((

 

& &?F$\ "\
 #T %h/ 	 #
 
 ]F$H $i
 
 IF$X  u %#6 
 &#b! 
 
 !	
 
 YF$~ ) S#$h/#    '

 

   F$\ ! Z %#P 
 &#i! 
 
 !	
 
 ]F$B  T %#Z 
 &#V!  &#g # #    %
 
 CF$r !, c %#s 
 %#^   
 &#V!  %"FO#p%	  
 
# #sF$j * s %#: 
 %#j 
 %#W   
 &#V!  &#R # #% 0 !	5
 
! !kF$j ) A &#[!  &#p$! ! 
 
   kF$P $/ e%#[! 	
 	
& &QF$l % B$$f-#Q&	! !

 

 mF$J  A
 
 KF$Z % I!#$h/#y$ $ ++

 

 [F$x & X$ $Q  #	
 	
 yF$V	 & s
 
  & d %#f# #
 %??? $[%	   **
 
 e	F$ F$ F$tCc3h  F F FT
 
/	
	
#$	/	
&'	
$%	
 	)d38n% 	 	 	 
/	
1 d38n-    

 	
#$	
)*	/	/	
 	
 	
	
	
#$	
 	
 !!'tDcN#   2 

#$	/	
	
)*	
 	
	4 Dc3h0 	 	 	" 

#$	/	
	
)*	
4 Dc3h0   & "&\ \w/0\\ \ *	\
 \ c\ \ $J\ 4Z\ \ \ \ \F  3 333 *3 Dj	3
 3 
&.3 3 3 3x  $$(,4 ,4,4,4 ,4 	,4
 ,4 I,4 E{T!,4 ,4 ,4 ,4 ,4h  N NNN *N c	N
 DjN 
&.N N N Nj  	M MM*M M Dj	M
 
#tCy.M M M M` ' ' ' ' ' ' ' '4  $	x x x	xS#Xx *	x
 x x x xvC	C"&sCx.CC C C C	"&sCx.   	"&sCx.   `	`"&sCx.`` ` ` `F+	+"&sCx.++ + + +6W	W"&sCx.WW W W Wt+	+"&sCx.++ + + +8'?	'?"&sCx.'?'? '? '? '?T++	++"&sCx.++++ ++ ++ ++\g#* g# g(T/C:O g g g g:+	:+"&sCx.:+:+ :+ :+ :+zB?	B?"&sCx.B?B? B? B? B?JR	R"&sCx.RR R R R6b	b"&sCx.bb b b b0Q	Q"&sCx.QQ Q Q Q*[ d38n QT    "2	2"&sCx.22 2 2 2j0	0"&sCx.00 0 0 0 %	 %"&sCx. % %  %  %  %F ,5fn-tFN/CCDE ,MP , ,  ,  ,  ,FY#	Y#"&sCx.Y#Y# Y# Y# Y#zK6K#%JK $%JK 0	K
 4K *K >K .K *K !"DK  @K >K $%JK 6K *K  6!K" 8#K$ 76'K K KS(Kc3h#@##EFFG   6  $48$)#26!"&k kkk k *	k
 6>*T1k "k k )4/k $Jk d
k 4Zk sDcN#S()k k k k\1R	1R 1R 	1R
 1R 38n1R 1R 1R 1R :1R 
1R 1R 1R 1Rh&3 &3 & & & & 	"d
 	"sTz 	" 	" 	" 	" 	" 	"r)   