"""Sovereign Intersymbolic Memory Layer. Bridges Neural (LLM) and Symbolic (Graph) reasoning by extracting structured triples from unstructured text and performing graph lookups. """ import logging import json from typing import List, Dict, Any from agent.gemini_adapter import GeminiAdapter from tools.graph_store import GraphStore logger = logging.getLogger(__name__) class SymbolicMemory: def __init__(self): self.adapter = GeminiAdapter() self.store = GraphStore() def ingest_text(self, text: str): """Extracts triples from text and adds them to the graph.""" prompt = f""" Extract all meaningful entities and their relationships from the following text. Format the output as a JSON list of triples: [{{"s": "subject", "p": "predicate", "o": "object"}}] Text: {text} Guidelines: - Use clear, concise labels for entities and predicates. - Focus on stable facts and structural relationships. - Predicates should be verbs or descriptive relations (e.g., 'is_a', 'works_at', 'collaborates_with'). """ try: result = self.adapter.generate( model="gemini-3.1-pro-preview", prompt=prompt, system_instruction="You are Timmy's Symbolic Extraction Engine. Extract high-fidelity knowledge triples.", response_mime_type="application/json" ) triples = json.loads(result["text"]) if isinstance(triples, list): count = self.store.add_triples(triples) logger.info(f"Ingested {count} new triples into symbolic memory.") return count except Exception as e: logger.error(f"Symbolic ingestion failed: {e}") return 0 def get_context_for(self, topic: str) -> str: """Performs a 2-hop graph search to find related context for a topic.""" # 1. Find direct relations direct = self.store.query(subject=topic) + self.store.query(object=topic) # 2. Find 2nd hop related_entities = set() for t in direct: related_entities.add(t['s']) related_entities.add(t['o']) extended = [] for entity in related_entities: if entity == topic: continue extended.extend(self.store.query(subject=entity)) all_triples = direct + extended if not all_triples: return "" context = "Symbolic Knowledge Graph Context:\n" for t in all_triples: context += f"- {t['s']} --({t['p']})--> {t['o']}\n" return context