82 lines
3.2 KiB
Python
82 lines
3.2 KiB
Python
"""
|
|
Defines the abstract interface for Emma's memory systems and provides a
|
|
non-persistent, in-memory implementation for testing.
|
|
"""
|
|
from abc import ABC, abstractmethod
|
|
from typing import List, Dict, Any, Optional
|
|
from contracts.common import EmmaConversation, MemoryRecord, AuditEvent, CallEmmaRequest
|
|
|
|
class MemoryStore(ABC):
|
|
"""Abstract Base Class for all memory store implementations."""
|
|
|
|
@abstractmethod
|
|
async def create_conversation(self, owner_id: str, workspace_id: str, created_by: str) -> EmmaConversation:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def get_conversation(self, conversation_id: str, owner_id: str) -> Optional[EmmaConversation]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def append_message(self, conversation_id: str, message: Dict[str, Any]) -> None:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def list_messages(self, conversation_id: str, limit: int = 50) -> List[Dict[str, Any]]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def store_memory(self, record: MemoryRecord) -> None:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def recall_memory(self, embedding: List[float], owner_id: str, scopes: List[str]) -> List[MemoryRecord]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def record_audit_event(self, event: AuditEvent) -> str:
|
|
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._messages: Dict[str, List[Dict[str, Any]]] = {}
|
|
self._memories: List[MemoryRecord] = []
|
|
self._audit: List[AuditEvent] = []
|
|
print("WARNING: InMemoryMemoryStore is active. Data will not be persisted.")
|
|
|
|
async def create_conversation(self, owner_id: str, workspace_id: str, created_by: str) -> EmmaConversation:
|
|
convo = EmmaConversation(owner_id=owner_id, workspace_id=workspace_id, created_by=created_by)
|
|
self._conversations[convo.conversation_id] = convo
|
|
self._messages[convo.conversation_id] = []
|
|
return convo
|
|
|
|
async def get_conversation(self, conversation_id: str, owner_id: str) -> Optional[EmmaConversation]:
|
|
convo = self._conversations.get(conversation_id)
|
|
if convo and convo.owner_id == owner_id:
|
|
return convo
|
|
return None
|
|
|
|
async def append_message(self, conversation_id: str, message: Dict[str, Any]) -> None:
|
|
if conversation_id in self._messages:
|
|
self._messages[conversation_id].append(message)
|
|
|
|
async def list_messages(self, conversation_id: str, limit: int = 50) -> List[Dict[str, Any]]:
|
|
return self._messages.get(conversation_id, [])[-limit:]
|
|
|
|
async def store_memory(self, record: MemoryRecord) -> None:
|
|
if record.owner_id:
|
|
self._memories.append(record)
|
|
|
|
async def recall_memory(self, embedding: List[float], owner_id: str, scopes: List[str]) -> List[MemoryRecord]:
|
|
recalled = [mem for mem in self._memories if mem.owner_id == owner_id]
|
|
return recalled[:5]
|
|
|
|
async def record_audit_event(self, event: AuditEvent) -> str:
|
|
self._audit.append(event)
|
|
return event.event_id
|