"""Session model and in-memory session store."""
import uuid
from abc import ABC, abstractmethod
from datetime import datetime, timezone
from pydantic import BaseModel, Field
from navi.llm.base import Message
class Session(BaseModel):
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
profile_id: str
messages: list[Message] = Field(default_factory=list)
pinned: bool = False
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
last_active: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
class SessionStore(ABC):
@abstractmethod
async def create(self, profile_id: str) -> Session: ...
@abstractmethod
async def get(self, session_id: str) -> Session | None: ...
@abstractmethod
async def save(self, session: Session) -> None: ...
@abstractmethod
async def list_all(self) -> list[Session]: ...
@abstractmethod
async def delete(self, session_id: str) -> bool: ...
@abstractmethod
async def set_pinned(self, session_id: str, pinned: bool) -> bool: ...
class InMemorySessionStore(SessionStore):
def __init__(self) -> None:
self._sessions: dict[str, Session] = {}
async def create(self, profile_id: str) -> Session:
session = Session(profile_id=profile_id)
self._sessions[session.id] = session
return session
async def get(self, session_id: str) -> Session | None:
return self._sessions.get(session_id)
async def save(self, session: Session) -> None:
session.last_active = datetime.now(timezone.utc)
self._sessions[session.id] = session
async def list_all(self) -> list[Session]:
return sorted(
self._sessions.values(),
key=lambda s: (s.pinned, s.last_active),
reverse=True,
)
async def delete(self, session_id: str) -> bool:
if session_id in self._sessions:
del self._sessions[session_id]
return True
return False
async def set_pinned(self, session_id: str, pinned: bool) -> bool:
s = self._sessions.get(session_id)
if s is None:
return False
s.pinned = pinned
return True