feat(memory): add provider interface (#72)

This commit is contained in:
Nicholai
2026-06-04 09:26:11 -06:00
committed by GitHub
parent a7e60ca7ec
commit c916224510
4 changed files with 538 additions and 31 deletions

View File

@@ -7,6 +7,7 @@ import os
from .memory import MemoryManager
from .memory_vector import MemoryVectorStore
from src.memory_provider import MemoryRecord, NativeMemoryProvider
@dataclass
@@ -42,6 +43,10 @@ class MemoryService:
self.vector_store = MemoryVectorStore(data_dir) if os.path.exists(
os.path.join(data_dir, "memory_vectors")
) else None
self.provider = NativeMemoryProvider(self.manager, self.vector_store)
def _sync_provider(self) -> None:
self.provider.memory_vector = self.vector_store
@staticmethod
def _to_memory(entry: Dict[str, Any], metadata: Optional[Dict[str, Any]] = None) -> Memory:
@@ -53,6 +58,19 @@ class MemoryService:
metadata=metadata or {},
)
@staticmethod
def _record_to_memory(record: MemoryRecord, metadata: Optional[Dict[str, Any]] = None) -> Memory:
merged_metadata = dict(record.metadata)
if metadata:
merged_metadata.update(metadata)
return Memory(
id=record.id,
text=record.text,
timestamp=record.timestamp,
session_id=record.session_id,
metadata=merged_metadata,
)
async def remember(self, text: str, session_id: Optional[str] = None) -> Memory:
"""
Store a new memory.
@@ -64,19 +82,9 @@ class MemoryService:
Returns:
Created Memory object
"""
entry = self.manager.add_entry(text)
if session_id:
entry["session_id"] = session_id
memories = self.manager.load_all()
memories.append(entry)
self.manager.save(memories)
# Also add to vector store if available
if self.vector_store and self.vector_store.healthy:
self.vector_store.add(entry["id"], entry["text"])
return self._to_memory(entry)
self._sync_provider()
record = await self.provider.remember(text, session_id=session_id)
return self._record_to_memory(record)
async def recall(self, query: str, top_k: int = 5) -> MemorySearchResult:
"""
@@ -89,28 +97,20 @@ class MemoryService:
Returns:
MemorySearchResult with matching memories
"""
# Try vector search first
all_memories = self.manager.load_all()
by_id = {m.get("id"): m for m in all_memories}
if self.vector_store and self.vector_store.healthy:
results = self.vector_store.search(query, k=top_k)
found = []
for result in results:
entry = by_id.get(result.get("memory_id"))
if entry:
found.append(self._to_memory(entry, metadata={"score": result.get("score")}))
if found:
return MemorySearchResult(memories=found, query=query, total=len(found))
# Fallback to keyword search
results = self.manager.get_relevant_memories(query, all_memories, max_items=top_k)
memories = [self._to_memory(m) for m in results]
self._sync_provider()
results = await self.provider.recall(query, top_k=top_k)
memories = [
self._record_to_memory(hit.memory, metadata={"score": hit.score})
if hit.score is not None
else self._record_to_memory(hit.memory)
for hit in results
]
return MemorySearchResult(memories=memories, query=query, total=len(memories))
def get_all(self, limit: int = 100) -> List[Memory]:
"""Get all memories."""
memories = self.manager.load_all()[:limit]
return [self._to_memory(m) for m in memories]
records = self.manager.load_all()[:limit]
return [self._to_memory(m) for m in records]
def delete(self, memory_id: str) -> bool:
"""Delete a memory by ID."""