OSVauco/opax-mcp/persistence/memory_store.py

62 lines
2.2 KiB
Python

"""
Defines the abstract interface for Emma's memory systems.
"""
from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional
from contracts.common import EmmaConversation, MemoryRecord
class MemoryStore(ABC):
"""Abstract Base Class for all memory store implementations."""
@abstractmethod
async def get_conversation(self, conversation_id: str, owner_id: str) -> Optional[EmmaConversation]:
pass
@abstractmethod
async def save_conversation(self, conversation: EmmaConversation) -> None:
pass
@abstractmethod
async def store_memory(self, record: MemoryRecord) -> None:
pass
@abstractmethod
async def recall_memory(self, embedding: List[float], owner_id: str, scope: List[str]) -> List[MemoryRecord]:
pass
class InMemoryMemoryStore(MemoryStore):
"""
A non-persistent, in-memory implementation of the MemoryStore for testing and
local development. DO NOT USE IN PRODUCTION.
"""
def __init__(self):
self._conversations: Dict[str, EmmaConversation] = {}
self._memories: List[MemoryRecord] = []
print("WARNING: InMemoryMemoryStore is active. Data will not be persisted.")
async def get_conversation(self, conversation_id: str, owner_id: str) -> Optional[EmmaConversation]:
convo = self._conversations.get(conversation_id)
# Enforce ownership check
if convo and convo.owner_id == owner_id:
return convo
return None
async def save_conversation(self, conversation: EmmaConversation) -> None:
# Enforce ownership
if conversation.owner_id:
self._conversations[conversation.conversation_id] = conversation
async def store_memory(self, record: MemoryRecord) -> None:
# Enforce ownership
if record.owner_id:
self._memories.append(record)
async def recall_memory(self, embedding: List[float], owner_id: str, scope: List[str]) -> List[MemoryRecord]:
# Simple text match for testing, no real embedding search.
# Also filters on ownership.
recalled = [mem for mem in self._memories if mem.owner_id == owner_id]
return recalled[:5] # Return top 5 for simplicity