guide / src /api /sessions.py
anmol-iisc's picture
UI Enhancements + privacy audit tab
4070852
Raw
History Blame Contribute Delete
3.04 kB
"""
Session registry β€” maps session_id β†’ Session (agent + conversation history).
In the initial implementation this is a module-level dict (in-process).
Replace with Redis or another distributed store for horizontal scaling.
Each session holds:
agent : GUIDEAgent instance (stateful CMA)
history : ordered list of {role, content} turn dicts
created_at : ISO-8601 UTC timestamp string
"""
from __future__ import annotations
import uuid
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import TYPE_CHECKING
from fastapi import HTTPException
if TYPE_CHECKING:
from src.agent.agent import GUIDEAgent
# ---------------------------------------------------------------------------
# Session container
# ---------------------------------------------------------------------------
@dataclass
class Session:
agent: "GUIDEAgent"
history: list[dict] = field(default_factory=list)
# Privacy audit trail β€” append-only log of every event where data either
# left the process (outbound to Anthropic) or was processed locally.
audit: list[dict] = field(default_factory=list)
created_at: str = field(
default_factory=lambda: datetime.now(timezone.utc).isoformat()
)
_sessions: dict[str, Session] = {}
# ---------------------------------------------------------------------------
# Registry operations
# ---------------------------------------------------------------------------
def create_session() -> str:
"""
Create a new GUIDEAgent session, register it, and return the session_id.
The session_id is a random UUID-4 string.
"""
from src.agent.agent import GUIDEAgent # local import avoids circular deps
session_id = str(uuid.uuid4())
_sessions[session_id] = Session(agent=GUIDEAgent(session_id))
return session_id
def get_session(session_id: str) -> Session:
"""
Return the Session for *session_id*.
Raises HTTP 404 (not KeyError) so callers in route handlers can let the
exception propagate directly to FastAPI without extra wrapping.
"""
session = _sessions.get(session_id)
if session is None:
raise HTTPException(
status_code=404,
detail=f"Session '{session_id}' not found. "
"Create one with POST /api/session/create.",
)
return session
def append_history(session_id: str, role: str, content: str) -> None:
"""Append a turn to the session's conversation history."""
_sessions[session_id].history.append({"role": role, "content": content})
def append_audit(session_id: str, entry: dict) -> None:
"""Append an event to the session's privacy audit trail."""
_sessions[session_id].audit.append(entry)
def delete_session(session_id: str) -> None:
"""Remove *session_id* from the registry (idempotent)."""
_sessions.pop(session_id, None)
def session_count() -> int:
"""Return the number of active sessions (used by the health endpoint)."""
return len(_sessions)