Coverage for /home/admin/Documents/AI/applications/lexigram-dev/lexigram/experimental/ai/lexigram-ai-memory/src/lexigram/ai/memory/semantic/store.py: 51%
37 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 07:19 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 07:19 +0800
1"""Semantic memory store — structured subject/predicate/object knowledge."""
3from __future__ import annotations
5from typing import TYPE_CHECKING, Any
7from lexigram.ai.memory.semantic.fact_store import FactStore
8from lexigram.contracts.core import HealthCheckResult, HealthStatus
9from lexigram.logging import (
10 get_logger,
11)
13if TYPE_CHECKING:
14 from lexigram.ai.memory.semantic.entity_extractor import EntityExtractor
15 from lexigram.contracts.ai.memory import MemoryEntry
17logger = get_logger(__name__)
20class SemanticMemoryStore:
21 """Semantic memory backed by an in-process FactStore."""
23 def __init__(
24 self,
25 fact_store: FactStore | None = None,
26 extractor: EntityExtractor | None = None,
27 min_confidence: float = 0.5,
28 max_facts_per_entity: int = 100,
29 ) -> None:
30 self._facts = fact_store or FactStore()
31 self._extractor = extractor
32 self._min_confidence = min_confidence
33 self._max_facts = max_facts_per_entity
35 async def store_fact(
36 self,
37 subject: str,
38 predicate: str,
39 object_: str,
40 confidence: float = 1.0,
41 ) -> str:
42 existing = self._facts.query_by_subject(subject)
43 if len(existing) >= self._max_facts:
44 logger.warning(
45 "semantic_max_facts_reached",
46 subject=subject,
47 cap=self._max_facts,
48 )
49 lowest = min(existing, key=lambda fact: fact["confidence"])
50 self._facts.delete(lowest["id"])
52 return self._facts.add(subject, predicate, object_, confidence)
54 async def query_facts(self, subject: str) -> list[dict[str, Any]]:
55 return [
56 fact
57 for fact in self._facts.query_by_subject(subject)
58 if fact["confidence"] >= self._min_confidence
59 ]
61 async def get_entity_facts(self, entity: str) -> list[dict[str, Any]]:
62 return [
63 fact
64 for fact in self._facts.get_entity_facts(entity)
65 if fact["confidence"] >= self._min_confidence
66 ]
68 async def update_fact(self, fact_id: str, confidence: float) -> None:
69 self._facts.update_confidence(fact_id, confidence)
71 async def ingest(self, entry: MemoryEntry) -> int:
72 if not self._extractor:
73 return 0
74 triples = await self._extractor.extract(entry)
75 count = 0
76 for subject, predicate, object_ in triples:
77 await self.store_fact(subject, predicate, object_, confidence=0.8)
78 count += 1
79 return count
81 async def health_check(self, timeout: float = 5.0) -> HealthCheckResult:
82 return HealthCheckResult(
83 component="memory.semantic",
84 status=HealthStatus.HEALTHY,
85 details={"facts": len(self._facts), "timeout": timeout},
86 )
89__all__ = ["SemanticMemoryStore"]