
    yj{Q                     h   d Z ddlZddlZddlmZmZ ddlmZ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mZ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%m&Z&m'Z' ddl(m)Z)m*Z* ddl+m,Z,m-Z-m.Z.m/Z/ ddl0m1Z1 ddl2m3Z3  ej4        e5          Z6dedefdZ7 G d d          Z8dS )z
Core Dialectic Agent implementation.

This agent uses tools to gather context from the memory system
and synthesize responses to queries about a peer.
    N)AsyncIteratorCallable)Anycast)generate)crud)ConfiguredModelSettingsReasoningLevelsettings)
tracked_db)prompts)embedding_client)HonchoLLMCallResponseStreamingResponseWithMetadatahoncho_llm_call)LLMTelemetryContext)prometheus_metrics)DialecticCompletedEventEmbeddingCallPurposeemit)accumulate_metriclog_performance_metricslog_token_usage_metrics)DialecticComponents
TokenTypes)DIALECTIC_TOOLSDIALECTIC_TOOLS_MINIMALcreate_tool_executorsearch_memory)format_new_turn_with_timestamp)embedding_call_purposereasoning_levelreturnc                 :    t           j        j        |          j        S )N)r   	DIALECTICLEVELSMODEL_CONFIG)r"   s    :/DATA/AppData/hermes/projects/honcho/src/dialectic/core.py!_get_dialectic_level_model_configr)   .   s     $_5BB    c                   p   e Zd ZdZ	 	 	 	 d#dededz  dededee         dz  d	ee         dz  d
edz  defdZd$dZdededz  fdZ	dede
eeeeef         gef         eedz  ef         fdZdefdZ	 d%dededz  dedededededz  dedz  dededz  dededdfd Zdedefd!Zdedee         fd"ZdS )&DialecticAgenta  
    An agentic dialectic that iteratively gathers context to answer queries.

    Unlike the standard dialectic which pre-gathers all context before a single
    LLM call, this agent uses tools to strategically gather only the context
    needed to answer the specific query.
    Nlowworkspace_namesession_nameobserverobservedobserver_peer_cardobserved_peer_card
metric_keyr"   c	                     || _         || _        || _        || _        || _        || _        || _        || _        dt          j	        ||||          dg| _
        d| _        d| _        t                      | _        dS )a[  
        Initialize the dialectic agent.

        Args:
            workspace_name: Workspace identifier
            session_name: Session identifier (may be None for global queries)
            observer: The peer making the query
            observed: The peer being queried about
            observer_peer_card: Biographical information about the observer
            observed_peer_card: Biographical information about the observed peer
            metric_key: Optional key for logging metrics (if provided, agent won't log separately)
            reasoning_level: Level of reasoning to apply
        systemrolecontentFr   N)r.   r/   r0   r1   r2   r3   r4   r"   r   agent_system_promptmessages_session_history_initialized_prefetched_conclusion_countgenerate_nanoid_run_id)	selfr.   r/   r0   r1   r2   r3   r4   r"   s	            r(   __init__zDialecticAgent.__init__=   s    0 $2(4%%4F4F&0/>
 !"6h(:<N  /
 38)12)+--r*   r#   c                   K   | j         rdS d| _         t          j        j        }|dk    s| j        sdS t          j        | j        | j        |d           d{V }t          d          4 d{V }|	                    |           d{V }|
                                                                }|s	 ddd          d{V  dS g }|D ]7}t          |j        |j        |j                  }|                    |           8	 ddd          d{V  n# 1 d{V swxY w Y   dt#          d                              |           d	}	| j        d         d
xx         |	z  cc<   dS )zFFetch and inject session history into the system prompt if configured.NTr   F)r.   r/   token_limitreversezdialectic.session_historyz

## SESSION HISTORY

The following is the recent conversation history from this session. Use this as immediate context when answering the query.

<session_history>

   z
</session_history>r9   )r<   r   r%   SESSION_HISTORY_MAX_TOKENSr/   r   get_messagesr.   r   executescalarsallr    r9   
created_at	peer_nameappendchrjoinr;   )
r@   
max_tokensstmtdbresultr;   formatted_messagesmsg	formattedsession_history_sections
             r(   _initialize_session_historyz*DialecticAgent._initialize_session_historyk   s     , 	F,0)'B
??$"3?F &.*"	
 
 
 
 
 
 
 
 
 9:: 	5 	5 	5 	5 	5 	5 	5b::d++++++++F~~''++--H 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 -/ 5 5:K 	 #)))4444	5	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 ! 2ww||.//	! ! ! 	  	a###'>>#####s   0AD<D
D!$D!queryc           	        K   | j         dk    rdnd}	 t          t          j        j        | j        | j        d          5  t          j        |           d{V }ddd           n# 1 swxY w Y   t          | j        | j
        | j        ||dg|           d{V }t          | j        | j
        | j        ||g d	|           d{V }|                                r|                                rdS |                                |                                z   | _        g }|                                s)|                    |                    d
                     |                                s)|                    |                    d                     d                    |          S # t$          $ r(}t&                              d|            Y d}~dS d}~ww xY w)a  
        Prefetch semantically relevant observations for the query.

        This provides immediate context to the agent without requiring
        tool calls, improving response quality and speed.

        Performs two separate searches to prevent retrieval dilution:
        - Explicit observations (produced by deriver)
        - Higher-level observations (produced in dreaming/background/chat)

        The number of observations fetched depends on reasoning level:
        - minimal: 10 of each type (reduced context for cost savings)
        - all others: 25 of each type

        Args:
            query: The user's query

        Returns:
            Formatted observations string or None if no observations found
        minimalrE      	dialectic)r.   run_idparent_categoryNexplicit)r.   r0   r1   rY   limitlevels	embedding)	deductive	inductivecontradictionF)include_idsT
z!Failed to prefetch observations: )r"   r!   r   DIALECTIC_PREFETCHvaluer.   r?   r   embedr   r0   r1   is_emptylenr=   rM   format_as_markdownrO   	Exceptionloggerwarning)r@   rY   prefetch_limitquery_embeddingexplicit_reprderived_reprpartses           r(   _prefetch_relevant_observationsz.DialecticAgent._prefetch_relevant_observations   s     ,  $3y@@b7	'$7=#2| +	   F F )9(>u(E(E"E"E"E"E"E"EF F F F F F F F F F F F F F F #0#2$"|)# # #      M "/#2$BBB)" " "      L %%'' L,A,A,C,C t 1>0A0A0C0ClFVFVFXFX0XD-  "E ))++ R]==%=PPQQQ((** P\<<<NNOOO99U### 	 	 	NNBqBBCCC44444	sB   ,F3 A&F3 &A**F3 -A*.BF3 4B>F3 3
G%=G  G%c                   K   |                                   d{V  d}| j        r| j        }nt                      }d| }t          j                    }t          |dd| j         d| j        pd d| j         d| j	         d	| j
         
d
           t          |d|d
           |                     |           d{V }|rd| d| }t          |d|d
           nd| }| j                            d|d           t          | j        | j        | j        | j	        t          j        j        | j        dd           d{V }||||fS )au  
        Prepare common state for answering a query.

        Handles session history initialization, metrics setup, observation prefetching,
        user message construction, and tool executor creation.

        Args:
            query: The question to answer about the peer

        Returns:
            A tuple of (tool_executor, task_name, run_id, start_time)
        Ndialectic_chat_contextzworkspace: z

session: z(global)z
observer: z
observed: z
reasoning_level: blobrY   zQuery: z

## Relevant Observations (prefetched)
The following observations were found to be semantically relevant to your query. Use these as primary context. You may still use tools to find additional information if needed.

prefetched_observationsuserr7   r]   )r.   r/   r0   r1   history_token_limitr^   
agent_typer_   )rX   r4   r>   timeperf_counterr   r.   r/   r0   r1   r"   rx   r;   rM   r   r   r%   HISTORY_TOKEN_LIMITr?   )r@   rY   r^   	task_name
start_timer}   user_contenttool_executors           r(   _prepare_queryzDialecticAgent._prepare_query   s      ..000000000!? 	3II$&&F2&22I&((
;d1 ; ; -;; ;!]; ; "]; ; %)$8	; ; 	
 	
 	
 	)WeV<<<(,(L(LU(S(S"S"S"S"S"S"S" 	--% - - +	- -  46Mv    -U,,LfFFGGG '.*]] ( 2 F<"'	
 	
 	
 	
 	
 	
 	
 	
 	
 	 i;;r*   c                 J    t          | j        ddd| j        | j                  S )aJ  Build the LLMTelemetryContext shared by answer() and answer_stream().

        Carries the instance's `_run_id` (always set in __init__) + workspace +
        peer identifiers so LLMCallCompletedEvent and 's
        AgentIterationEvent can attribute every per-iteration LLM call back to
        this dialectic invocation.
        zdialectic.answerr]   )r.   call_purposer_   r   r^   rL   )r   r.   r?   r1   )r@   s    r(   _telemetry_contextz!DialecticAgent._telemetry_context0  s4     #.+'"<m
 
 
 	
r*   Fr   r^   r   response_contentinput_tokensoutput_tokenscache_read_input_tokenscache_creation_input_tokenstool_calls_countthinking_content
iterationshit_input_token_capc                    t          |d|	d           |
rt          |d|
d           t          ||||pd|pd           t          |d|d           t          j                    |z
  dz  }t          |d|d	           | j        s|t          d|           t          j        j        rvt          j
        |t          j        j        t          j        j        | j                   t          j
        |t          j        j        t          j        j        | j                   t%          t'          | j        | j        | j        | j        | j        || j        |	||||pd|pd|                     d
S )a  
        Log metrics common to both streaming and non-streaming responses.

        Args:
            task_name: Metrics task identifier
            run_id: Run identifier (None if using caller-provided metric_key)
            start_time: Start time from time.perf_counter()
            response_content: The full response text
            input_tokens: Input token count (actual from API)
            output_tokens: Output token count (actual from API)
            cache_read_input_tokens: Cache read tokens (if any)
            cache_creation_input_tokens: Cache creation tokens (if any)
            tool_calls_count: Number of tool calls made
            thinking_content: Thinking trace content (if any)
            iterations: Number of iterations in the tool execution loop
        
tool_callscountthinkingr|   r   responsei  total_durationmsNdialectic_chat)r   
token_type	componentr"   )r^   r.   rL   r/   r"   total_iterationsprefetched_conclusion_countr   total_duration_msr   r   cache_read_tokenscache_creation_tokensr   )r   r   r   r   r4   r   r   METRICSENABLEDr   record_dialectic_tokensr   INPUTrj   r   TOTALr"   OUTPUTr   r   r?   r.   r1   r/   r=   )r@   r   r^   r   r   r   r   r   r   r   r   r   r   
elapsed_mss                 r(   _log_response_metricsz$DialecticAgent._log_response_metricsA  s   > 	)\3CWMMM 	Oi5EvNNN#(q',1	
 	
 	
 	)Z1A6JJJ'))J6$>
)%5z4HHH 	>6#5#$4f=== # 	6"%+1-39 $ 4	    6#%,2-39 $ 4	    	#|#2-!. $ 4!+,0,M!1",)+"9">Q&A&FQ$7  	
 	
 	
 	
 	
r*   c                 x  K   |                      |           d{V \  }}}}t          j        j        | j                 }| j        dk    rt
          nt          }|j        |j        nt          j        j        }t          t          | j                  d|||j
        ||j        | j        dt          j        j        d|                                            d{V }	|                     ||||	j        |	j        |	j        |	j        |	j        t+          |	j                  |	j        |	j        |	j                   |	j        S )aw  
        Answer a query about the peer using agentic tool calling.

        The agent will:
        1. Receive the query
        2. Use tools to gather relevant context
        3. Synthesize a response grounded in the gathered context

        Args:
            query: The question to answer about the peer

        Returns:
            The synthesized answer string
        Nr[    zDialectic Agentr   )model_configpromptrP   toolstool_choicer   max_tool_iterationsr;   
track_namemax_input_tokens
trace_name	telemetryr   r^   r   r   r   r   r   r   r   r   r   r   )r   r   r%   r&   r"   r   r   MAX_OUTPUT_TOKENSr   r)   TOOL_CHOICEMAX_TOOL_ITERATIONSr;   MAX_INPUT_TOKENSr   r   r9   r   r   r   r   rm   tool_calls_mader   r   r   )
r@   rY   r   r   r^   r   level_settingsr   rP   r   s
             r(   answerzDialecticAgent.answer  s      >B=P=PQV=W=W7W7W7W7W7W7W4y&* "+243GH
 #y00 $#  	 /; ,,#5 	 6E:4;OPP!&2' . B](%/@'--//6
 6
 6
 0
 0
 0
 0
 0
 0
 	""!%-!."0$,$D(0(L !9::%6* ( < 	# 	
 	
 	
 r*   c                $  K   |                      |           d{V \  }}}}t          j        j        | j                 }| j        dk    rt
          nt          }|j        |j        nt          j        j        }t          t          t          t          | j                  d|dd||j        ||j        | j        dt          j        j        d|                                            d{V           }	g }
|	2 3 d{V }|j        r$|
                    |j                   |j        W V  36 |                     |||d                    |
          |	j        |	j        |	j        |	j        t3          |	j                  |	j        |	j        |	j                   dS )	a  
        Answer a query about the peer using agentic tool calling, streaming the response.

        The agent will:
        1. Receive the query
        2. Use tools to gather relevant context (non-streaming)
        3. Stream the synthesized response

        Args:
            query: The question to answer about the peer

        Yields:
            Chunks of the response text as they are generated
        Nr[   r   TzDialectic Agent Streamr   )r   r   rP   streamstream_final_onlyr   r   r   r   r;   r   r   r   r   r   )r   r   r%   r&   r"   r   r   r   r   r   r   r)   r   r   r;   r   r   r9   rM   r   rO   r   r   r   r   rm   r   r   r   r   )r@   rY   r   r   r^   r   r   r   rP   r   accumulated_contentchunks               r(   answer_streamzDialecticAgent.answer_stream  s      >B=P=PQV=W=W7W7W7W7W7W7W4y&* "+243GH
 #y00 $#  	 /; ,,#5 	 )!>t?STT%"&*6+$2$F3!)!3!D+1133        
 
( *,# 	$ 	$ 	$ 	$ 	$ 	$ 	$%} $#**5=999m#### $
 	""!WW%899!."0$,$D(0(L !9::%6* ( < 	# 	
 	
 	
 	
 	
s   3D&)NNNr-   )r#   N)F)__name__
__module____qualname____doc__strlistr
   rA   rX   rx   tupler   dictr   floatr   r   r   intboolr   r   r   r    r*   r(   r,   r,   4   ss         04/3!%*/,. ,.,. Dj,. 	,.
 ,. !I,,. !I,,. $J,. (,. ,. ,. ,.\*? *? *? *?XO3 O3: O O O ObF<F<	xd38n-s23S#*eK	LF< F< F< F<P
$7 
 
 
 
< %*T
 T
T
 d
T
 	T

 T
 T
 T
 "%tT
 &)4ZT
 T
 *T
 T
 "T
 
T
 T
 T
 T
l? # ? # ?  ?  ?  ? BH
 H
s1C H
 H
 H
 H
 H
 H
r*   r,   )9r   loggingr   collections.abcr   r   typingr   r   nanoidr   r>   srcr   
src.configr	   r
   r   src.dependenciesr   src.dialecticr   src.embedding_clientr   src.llmr   r   r   src.llm.typesr   src.telemetryr   src.telemetry.eventsr   r   r   src.telemetry.loggingr   r   r    src.telemetry.prometheus.metricsr   r   src.utils.agent_toolsr   r   r   r   src.utils.formattingr    src.utils.typesr!   	getLoggerr   rp   r)   r,   r   r*   r(   <module>r      si      3 3 3 3 3 3 3 3         . . . . . .       H H H H H H H H H H ' ' ' ' ' ' ! ! ! ! ! ! 1 1 1 1 1 1         
 . - - - - - , , , , , , T T T T T T T T T T         
 M L L L L L L L            @ ? ? ? ? ? 2 2 2 2 2 2		8	$	$C#CC C C Cl
 l
 l
 l
 l
 l
 l
 l
 l
 l
r*   