
    Ni6                     r   d Z ddlZddlZddlZddlZddlmZmZ ddlmZ  ej                  d      Z
e
dz  dz  Ze
dz  dz  Zd	Zd
ZdZdZd!dZdee   fdZd"dedefdZdedee   fdZdededefdZdededefdZdededefdZd#dededefdZdededefdZdedefdZd!dZ e!d k(  r e         yy)$a  
kg_query_before_execution.py
-----------------------------
Auto-queries the Knowledge Graph before every Genesis task starts, and injects
the top N relevant axioms into the agent system prompt.

Usage (CLI):
    python3 core/kg_query_before_execution.py --query "build voice bridge" --top 5
    python3 core/kg_query_before_execution.py --query "build voice bridge" --top 5 --inject

Programmatic:
    from core.kg_query_before_execution import kg_preflight, inject_axioms_into_prompt
    N)datetimetimezone)Optionalz/mnt/e/genesis-systemKNOWLEDGE_GRAPHaxiomsentitiesz"qdrant-b3knu-u50607.vm.elestio.appi  genesis_memorieszmodels/gemini-embedding-001returnc                     t         dz  dz  } | j                         rt        |       5 }|D ]  }|j                         }|r|j	                  d      sd|vr+|j                  d      \  }}}|j                         }|j                         j                  d      j                  d      }|s|t        j                  vs|t        j                  |<    	 ddd       yy# 1 sw Y   yxY w)zILoad /mnt/e/genesis-system/config/secrets.env into os.environ if not set.configzsecrets.env#="'N)_GENESIS_ROOTexistsopenstrip
startswith	partitionosenviron)secrets_pathfhrawlinekey_vals          7/mnt/e/genesis-system/core/kg_query_before_execution.py	_load_envr!   +   s     8+m;L, 		*2 *yy{ts3s$"nnS1Qiikiik'',22373bjj0&)BJJsO*		* 		* 		* 		*s   BC,C?CC(c                  p    t                dD ]'  } t        j                  j                  |       }|s%|c S  y )N)GEMINI_API_KEY_NEWGEMINI_API_KEYGOOGLE_API_KEY)r!   r   r   get)varr   s     r    _gemini_api_keyr(   ;   s5    KI jjnnS!J     defaultc                    t        | t        t        f      rt        |       S t        | t              r;dddddd}| j	                         j                         }||v r||   S 	 t        |       S |S # t        t        f$ r |cY S w xY w)z>Convert val to float safely, mapping string confidence labels.gffffff?g?gffffff?g      ?g333333?)	very_highhighmediumlowvery_low)
isinstanceintfloatstrr   lower
ValueError	TypeError)r   r*   mappinglowereds       r    _safe_floatr:   D   s    #U|$Sz#sscC
 ))+##%g7##	: N I& 	N	s   "
A/ /BBtextc                    t               }|sy	 ddlm} |j                  |      }|j                  j                  t        | g      }t        |j                  d   j                        S # t        $ r}t        d|        Y d}~yd}~ww xY w)zCReturn embedding vector for text using Gemini gemini-embedding-001.Nr   )genai)api_key)modelcontentsz[kg_query] Gemini embed error: )r(   googler=   Clientmodelsembed_contentEMBED_MODELlist
embeddingsvalues	Exceptionprint)r;   r>   	new_genaiclientresponseexcs         r    _embed_textrO   Z   s    G-!!'!2==..V / 

 H''*1122 /u56s   AA+ +	B4BBvectortop_nc                    	 ddl m}  |dt         dt         t        j
                  j                  dd      dd	      }|j                  t        | |d
      }t        |d      r|j                  n|}g }|D ]  }|j                  xs i }|j                  d      xs |j                  d      xs d}	|j                  |	|j                  dd      t        |j                  dd            t        |j                        |j                  dt!        |j"                              d        |S # t$        $ r}
t'        d|
        g cY d}
~
S d}
~
ww xY w)z8Query Qdrant collection and return scored axiom records.r   )QdrantClientzhttps://:QDRANT_API_KEY@7b74e6621bd0e6650789f6662bca4cbf4143d3d1d710a0002b3b563973ca6876g       @F)urlr>   timeoutprefer_grpcT)collection_namequerylimitwith_payloadpointscontentaxiom sourceunknown
confidence        idr_   rb   rd   relevance_scorerf   z [kg_query] Qdrant query failed: N)qdrant_clientrS   QDRANT_HOSTQDRANT_PORTr   r   r&   query_pointsQDRANT_COLLECTIONhasattrr^   payloadappendr:   r3   scorer4   rf   rI   rJ   )rP   rQ   rS   rL   rM   r^   r   hitro   r_   rN   s              r    _query_qdrantrs   p   s=   .;-q6JJNN#35wx	
 &&-	 ' 
 %,Hh$?X 		Ckk'RGkk),JG0DJGMM#*#*;;x#C#.w{{</M#N#(#3#*;;tS[#A 		  067	s   D)D, ,	E5E
E
Er[   c                     t        |j                         j                               }t        | j                         j                               }|syt        ||z        t        |      z  S )z8Simple keyword overlap score (0-1) for fallback ranking.re   )setr5   splitlen)r;   r[   query_tokenstext_tokenss       r    _keyword_scorerz      sT    u{{}**,-Ltzz|))+,K|k)*S->>>r)   task_descriptionc                    g }t         j                         sg S t        t         j                  d            D ]  }	 t	        |dd      5 }|D ]  }|j                         }|s	 t        j                  |      }|j                  d      xs |j                  d      xs d}|sW|j                  ||j                  d|j                        t        |j                  d	d
            t        ||       |j                  dd      d        	 ddd        |j#                  d d       |d| S # t        j                  $ r Y w xY w# 1 sw Y   =xY w# t        $ r&}t        d|j                    d|        Y d}~Ed}~ww xY w)z?Scan all JSONL axiom files and return top N by keyword overlap.*.jsonlutf-8replaceencodingerrorsr_   r`   ra   rb   rd   re   rf   rg   Nz[kg_query] Error reading z: c                     | d   | d   fS )Nrh   rd    )xs    r    <lambda>z'_fallback_jsonl_query.<locals>.<lambda>   s    1%6#7<"I r)   T)r   reverse)_AXIOMS_DIRr   sortedglobr   r   jsonloadsJSONDecodeErrorr&   rp   stemr:   rz   rI   rJ   namesort)	r{   rQ   
candidates
jsonl_pathr   r   recordr_   rN   s	            r    _fallback_jsonl_queryr      s{   J	[--i89 
	j79E  D::<D !!%D!1 %jj3Pvzz'7JPbG" %%+2+1::h
+P+6vzz,PS7T+U+9'CS+T+1::dB+?' 2 OOISWOXfu#  // ! ! &  	-joo->bFG	sT   E	E#D-8BE
E-E	 EE	EE	E	FE<<Fc                 x   	 ddl m}  || |      }|r=|D cg c]1  }|j                  |j                  |j                  |j                  d3 c}S 	 t        |       }|rt        ||      }|r|S t        d       nt        d	       t        | |      S c c}w # t
        $ r}t        d| d       Y d}~bd}~ww xY w)
a8  
    Query the Knowledge Graph for axioms semantically relevant to task_description.

    Uses the unified Nervous System retriever (Qdrant + PG + KG files).
    Falls back to legacy pipeline if nervous system import fails.

    Returns:
        List of dicts: {content, source, confidence, relevance_score}
    r   )query_knowledge_structured)top_k)r_   rb   rd   rh   z%[kg_query] Unified retriever failed (u   ) — falling back to legacy.NuD   [kg_query] Qdrant returned 0 results — falling back to JSONL scan.u@   [kg_query] Embedding unavailable — falling back to JSONL scan.)
!core.nervous_system.runtime_queryr   r_   rb   rh   rI   rJ   rO   rs   r   )r{   rQ   r   chunkscrN   rP   resultss           r    get_relevant_axiomsr      s    ZP+,<EJ     !yyhh"#"3"3'('8'8	   )*F.NTUPQ !1599-  Z5cU:WXYYZs(   B 6BB B 	B9 B44B9base_promptc                 \   |s| S dg}t        |d      D ]R  \  }}|j                  | d|j                  dd       d|j                  dd	       d
|j                  dd       d       T |j                  d       |j                  d       |j                  |        dj                  |      S )z
    Prepend an axiom block to base_prompt.

    Output format:
        ## Relevant Genesis Axioms (auto-injected)
        1. [content] (source: X, confidence: Y)
        ...

        ## Task
        [base_prompt]
    z*## Relevant Genesis Axioms (auto-injected)   start. r_   ra   z
 (source: rb   rc   z, confidence: rd   re   )z## Task
)	enumeraterp   r&   join)r   r   linesidxaxs        r    inject_axioms_into_promptr      s     9:EV1- 
Re2bffY+, -x34 566,45Q8	

 
LL	LL	LL99Ur)   c                    t        | d      }d}d}t        j                         rGt        j                  d      D ]/  }	 t	        |dd      5 }|t        d |D              z  }d	d	d	       1 t        j                         rt        t        j                  d            t        t        j                  d
            z   D ]q  }	 t	        |dd      5 }|j                         j                         }d	d	d	       s<	 t        j                  |      }|t        |t              rt        |      ndz  }s t"        dz  dz  }|j                         r-	 t	        |dd      5 }|t        d |D              z  }d	d	d	       |||t%        j&                  t(        j*                        j-                         dS # 1 sw Y   PxY w# t        $ r Y w xY w# 1 sw Y   xY w# t        j                  $ r& |t        d |j!                         D              z  }Y w xY w# t        $ r Y dw xY w# 1 sw Y   xY w# t        $ r Y w xY w)a`  
    Full KG preflight for a task.

    Returns:
        {
            axioms:        list[dict],  # top 3 relevant axioms
            entity_count:  int,         # total entity records across KG files
            axiom_count:   int,         # total axiom records across JSONL files
            timestamp:     str,         # ISO-8601 UTC
        }
       rQ   r   r}   r~   r   r   c              3   B   K   | ]  }|j                         sd   ywr   Nr   .0lns     r    	<genexpr>zkg_preflight.<locals>.<genexpr>  s     &DRq&D   Nz*.jsonr   c              3   B   K   | ]  }|j                         sd   ywr   r   r   s     r    r   zkg_preflight.<locals>.<genexpr>.  s     'Sb
'Sr   r   zentities.jsonlc              3   B   K   | ]  }|j                         sd   ywr   r   r   s     r    r   zkg_preflight.<locals>.<genexpr>6  s     #A"bhhjA#Ar   )r   entity_countaxiom_count	timestamp)r   r   r   r   r   sumrI   _ENTITIES_DIRrF   readr   r   r   r1   rw   r   
splitlinesr   r   nowr   utc	isoformat)	r{   r   r   r   pr   r   parsedentities_roots	            r    kg_preflightr   
  s(    !!1;FKL!!), 	A!gi@ EB3&D2&D#DDKE	 m((34tM<N<Nx<X7YY 	A!gi@ ,B'')//+C,T!ZZ_F :fd3KCKQRRL	 "$558HHM	mgiH BB#A#A AAB  %$!hll3==?	 9E E , , ++ T C'SCNN4D'S$SSLT B B 		s   F>F1#F>HG/
H;5GH2 H&3H2 1F;	6F>>	G
GG	H6HHHH	H#"H#&H/+H2 2	H>=H>c            
         t        j                  dt         j                  d      } | j                  dddd       | j                  d	d
t        dd       | j                  ddd       | j                         }t        d|j                   d|j                   d       |j                  dk(  r?t        |j                        }t        d|d    d|d           t        d|d    d       nSt        |j                  |j                        t        j                  t        j                        j                         d}|d   }|st        d       y t        d t!        |       d!       t#        |d"#      D ]A  \  }}t        d$| d%|d&           t        d'|d(    d)|d*    d+|d,   d-       t                C |j$                  r.t'        d.|      }t        d/       t        |       t        d0       y y )1Nz2Query Genesis Knowledge Graph for relevant axioms.z
Examples:
  python3 core/kg_query_before_execution.py --query "voice bridge MCP server" --top 3
  python3 core/kg_query_before_execution.py --query "build landing page" --top 5 --inject
)descriptionformatter_classepilogz--queryz-qTz/Task description to search for relevant axioms.)requiredhelpz--topz-nr   z,Number of top axioms to return (default: 3).)typer*   r   z--inject
store_truez6Print example of axioms injected into a sample prompt.)actionr   z
[kg_query] Querying KG for: 'z'  (top z)
u   KG Stats  — axioms: r   z  |  entities: r   u   Timestamp — r   r   r   )r   r   r   zNo axioms found.zTop z axiom(s) found:
r   r   z  r   r_   z     source: rb   z  |  confidence: rd   z  |  relevance: rh   z.4fzBuild the voice bridge module.z--- Injected prompt preview ---z--- end ---)argparseArgumentParserRawDescriptionHelpFormatteradd_argumentr2   
parse_argsrJ   r[   topr   r   r   r   r   r   r   rw   r   injectr   )parserargsresultr   ir   injecteds          r    _clir   E  s   $$H <<F 	4$N  P
CK  M

<U  WD	+DJJ<xz
MNxx1}djj)&vm'<&=_VTbMcLdefvk23267 -TZZtxxH!hll3==?

 HF !	DV/
016+ 21#R9'(bl^+<R=M<NN^_abs_tux^yz{
 {{,-MvV/0hm	 r)   __main__)r
   N)re   )r   )"__doc__r   r   r   pathlibr   r   typingr   Pathr   r   r   rj   rk   rm   rE   r!   r4   r(   r3   r:   rF   rO   r2   rs   rz   r   r   r   dictr   r   __name__r   r)   r    <module>r      s\   
    ' 
 45 11H< 11J>
 9&  ,* # e e ,c htn ,!$ !s !t !N? ?S ?U ? C      L$:# $:c $:$ $:N3   :53 54 5v-` zF r)   