|
11 | 11 | from .backends.sqlite import SQLiteBackend |
12 | 12 | from .core.engine import BrainTrace, DreamResult, ForgetResult |
13 | 13 | from .security.audit import AuditLogger |
14 | | -from .types import Memory, MemoryType, RetrievalExplanation |
| 14 | +from .types import Memory, MemoryTier, MemoryType, RetrievalExplanation |
15 | 15 |
|
16 | 16 | logger = logging.getLogger(__name__) |
17 | 17 |
|
@@ -101,6 +101,57 @@ def add( |
101 | 101 | self._audit.log("add", memory_id=memory_id_result, namespace=namespace, source=source) |
102 | 102 | return memory_id_result |
103 | 103 |
|
| 104 | + def add_experience( |
| 105 | + self, |
| 106 | + content: str, |
| 107 | + namespace: str = "default", |
| 108 | + source: str = "experience", |
| 109 | + confidence: float = 1.0, |
| 110 | + importance: Optional[float] = None, |
| 111 | + metadata: Optional[Dict] = None, |
| 112 | + ) -> str: |
| 113 | + """Graph-first ingestion for unstructured experience text.""" |
| 114 | + memory_id = self.brain.add_experience( |
| 115 | + content, |
| 116 | + namespace=namespace, |
| 117 | + source=source, |
| 118 | + confidence=confidence, |
| 119 | + importance=importance, |
| 120 | + metadata=metadata, |
| 121 | + ) |
| 122 | + self._audit.log("add_experience", memory_id=memory_id, namespace=namespace) |
| 123 | + return memory_id |
| 124 | + |
| 125 | + def link_entities( |
| 126 | + self, |
| 127 | + source: str, |
| 128 | + target: str, |
| 129 | + relation: str = "related_to", |
| 130 | + memory_id: str = "", |
| 131 | + confidence: float = 1.0, |
| 132 | + ) -> str: |
| 133 | + """Explicitly link two entities in the knowledge graph.""" |
| 134 | + return self.brain.link_entities( |
| 135 | + source, target, relation, memory_id=memory_id, confidence=confidence |
| 136 | + ) |
| 137 | + |
| 138 | + def assert_fact( |
| 139 | + self, |
| 140 | + subject: str, |
| 141 | + relation: str, |
| 142 | + obj: str, |
| 143 | + memory_id: str = "", |
| 144 | + confidence: float = 0.9, |
| 145 | + ) -> Dict: |
| 146 | + """Assert a structured fact as a high-confidence graph relation.""" |
| 147 | + return self.brain.assert_fact( |
| 148 | + subject, relation, obj, memory_id=memory_id, confidence=confidence |
| 149 | + ) |
| 150 | + |
| 151 | + def query_graph(self, entity_name: str, depth: int = 2) -> Dict: |
| 152 | + """Structured graph query: nodes, edges, and related memory IDs.""" |
| 153 | + return self.brain.query_graph(entity_name, depth=depth) |
| 154 | + |
104 | 155 | def add_batch( |
105 | 156 | self, |
106 | 157 | contents: List[str], |
@@ -143,16 +194,27 @@ def recall( |
143 | 194 | time_range: Optional[str] = None, |
144 | 195 | namespace: Optional[str] = None, |
145 | 196 | project_only: bool = False, |
| 197 | + level: Optional[str] = None, |
| 198 | + tiers: Optional[List[MemoryTier]] = None, |
| 199 | + explain: bool = False, |
| 200 | + weight_overrides: Optional[Dict] = None, |
| 201 | + include_archive: bool = False, |
146 | 202 | ) -> List[Memory]: |
147 | 203 | """Advanced retrieval with context-type boosting and temporal filtering. |
148 | 204 |
|
149 | 205 | Args: |
150 | 206 | query: The search query. |
151 | 207 | k: Number of results. |
152 | 208 | context_type: One of 'architecture', 'bugs', 'decisions', etc. |
| 209 | + mode: Retrieval mode profile ('default', 'planning', 'coding', 'chat', 'recall'). |
153 | 210 | time_range: One of 'today', 'recent', 'last_week'. |
154 | 211 | namespace: Specific namespace. |
155 | 212 | project_only: If True, only searches the provided namespace (doesn't mix global). |
| 213 | + level: Hierarchy filter ('working', 'short_term', 'long_term', 'archive'). |
| 214 | + tiers: Optional list of MemoryTier enums to restrict search. |
| 215 | + explain: If True, populate explanations via get_explanations(). |
| 216 | + weight_overrides: Optional dict to override fusion weight components. |
| 217 | + include_archive: Include archived memories in search. |
156 | 218 | """ |
157 | 219 | import time |
158 | 220 |
|
@@ -231,7 +293,17 @@ def recall( |
231 | 293 | ) |
232 | 294 |
|
233 | 295 | results = self.brain.rag( |
234 | | - query, top_k=top_k, namespace=search_namespace, type_boosts=type_boosts |
| 296 | + query, |
| 297 | + top_k=top_k, |
| 298 | + namespace=search_namespace, |
| 299 | + type_boosts=type_boosts, |
| 300 | + mode=mode or "default", |
| 301 | + level=level, |
| 302 | + tiers=tiers, |
| 303 | + explain=explain, |
| 304 | + weight_overrides=weight_overrides, |
| 305 | + include_archive=include_archive, |
| 306 | + include_inactive=include_archive, |
235 | 307 | ) |
236 | 308 |
|
237 | 309 | # Post-filter for namespace if we searched wide |
@@ -323,9 +395,33 @@ def inspect( |
323 | 395 | query: str, |
324 | 396 | top_k: int = 5, |
325 | 397 | namespace: Optional[str] = None, |
| 398 | + mode: str = "default", |
| 399 | + weight_overrides: Optional[Dict] = None, |
326 | 400 | ) -> List[RetrievalExplanation]: |
327 | | - """Explain the scoring for a given query.""" |
328 | | - return self.brain.inspect(query, top_k, namespace) |
| 401 | + """Explain the fusion scoring breakdown for a given query.""" |
| 402 | + return self.brain.inspect( |
| 403 | + query, |
| 404 | + top_k, |
| 405 | + namespace, |
| 406 | + mode=mode, |
| 407 | + weight_overrides=weight_overrides, |
| 408 | + ) |
| 409 | + |
| 410 | + def get_explanations(self) -> List[RetrievalExplanation]: |
| 411 | + """Return explanations from the last explain=True recall.""" |
| 412 | + return self.brain.get_last_explanations() |
| 413 | + |
| 414 | + def set_fusion_weights(self, weights: Dict[str, float]) -> None: |
| 415 | + """Set default fusion weights for retrieval scoring.""" |
| 416 | + from .core.retrieval.fusion import FusionWeights |
| 417 | + |
| 418 | + current = self.brain.get_fusion_weights().as_dict() |
| 419 | + current.update(weights) |
| 420 | + self.brain.set_fusion_weights(FusionWeights(**current)) |
| 421 | + |
| 422 | + def get_fusion_weights(self) -> Dict[str, float]: |
| 423 | + """Return current fusion weight configuration.""" |
| 424 | + return self.brain.get_fusion_weights().as_dict() |
329 | 425 |
|
330 | 426 | def namespace_stats(self, namespace: str) -> Dict: |
331 | 427 | """Get stats for a specific namespace.""" |
|
0 commit comments