ai / backend /rexpro_ai /models /memories.py
fdrah
initial-commit
9e93b10
Raw
History Blame Contribute Delete
4.97 kB
"""Long-term memory storage for per-user context recall."""
from __future__ import annotations
import time
import uuid
from typing import Optional
from rexpro_ai.internal.db import Base, get_async_db_context
from pydantic import BaseModel, ConfigDict
from sqlalchemy import BigInteger, Column, String, Text, delete, select
from sqlalchemy.ext.asyncio import AsyncSession
class Memory(Base): # user memory store
"""Stores user-created memory entries linked to a vector collection."""
__tablename__ = 'memory'
id = Column(String, primary_key=True, unique=True)
user_id = Column(String, index=True)
content = Column(Text) # free-form text learned from conversation
updated_at = Column(BigInteger) # epoch seconds
created_at = Column(BigInteger) # epoch seconds
class MemoryModel(BaseModel):
"""Pydantic mirror of the Memory table row."""
id: str
user_id: str
content: str
updated_at: int # timestamp in epoch
created_at: int # timestamp in epoch
model_config = ConfigDict(from_attributes=True) # allows ORM mapping
class MemoriesTable:
async def insert_new_memory(
self,
user_id: str,
content: str,
db: AsyncSession | None = None,
) -> MemoryModel | None:
"""Persist a new memory entry and return the created model."""
async with get_async_db_context(db) as db:
now = int(time.time())
record = Memory(
id=str(uuid.uuid4()),
user_id=user_id,
content=content,
created_at=now,
updated_at=now,
)
db.add(record)
await db.commit()
await db.refresh(record)
return MemoryModel.model_validate(record) if record else None
async def update_memory_by_id_and_user_id(
self,
id: str,
user_id: str,
content: str,
db: AsyncSession | None = None,
) -> MemoryModel | None:
async with get_async_db_context(db) as db:
try:
memory = await db.get(Memory, id)
if not memory or memory.user_id != user_id:
return None
memory.content = content
memory.updated_at = int(time.time())
await db.commit()
await db.refresh(memory)
return MemoryModel.model_validate(memory)
except Exception:
return None
async def get_memories(self, db: AsyncSession | None = None) -> list[MemoryModel]:
async with get_async_db_context(db) as db:
try:
result = await db.execute(select(Memory))
memories = result.scalars().all()
return [MemoryModel.model_validate(memory) for memory in memories]
except Exception:
return None
async def get_memories_by_user_id(self, user_id: str, db: AsyncSession | None = None) -> list[MemoryModel]:
async with get_async_db_context(db) as db:
try:
result = await db.execute(select(Memory).filter_by(user_id=user_id))
memories = result.scalars().all()
return [MemoryModel.model_validate(memory) for memory in memories]
except Exception:
return None
async def get_memory_by_id(self, id: str, db: AsyncSession | None = None) -> MemoryModel | None:
async with get_async_db_context(db) as db:
try:
memory = await db.get(Memory, id)
return MemoryModel.model_validate(memory) if memory else None
except Exception:
return None
async def delete_memory_by_id(self, id: str, db: AsyncSession | None = None) -> bool:
async with get_async_db_context(db) as db:
try:
await db.execute(delete(Memory).filter_by(id=id))
await db.commit()
return True
except Exception:
return False
async def delete_memories_by_user_id(self, user_id: str, db: AsyncSession | None = None) -> bool:
async with get_async_db_context(db) as db:
try:
await db.execute(delete(Memory).filter_by(user_id=user_id))
await db.commit()
return True
except Exception:
return False
async def delete_memory_by_id_and_user_id(self, id: str, user_id: str, db: AsyncSession | None = None) -> bool:
async with get_async_db_context(db) as db:
try:
memory = await db.get(Memory, id)
if not memory or memory.user_id != user_id:
return False
await db.delete(memory)
await db.commit()
return True
except Exception:
return False
Memories = MemoriesTable() # user memory registry