Newer
Older
navi-1 / navi / api / routes / sessions.py
"""Session management endpoints."""

from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel

from navi.api.deps import get_profile_registry, get_session_store
from navi.core import ProfileRegistry, SessionStore
from navi.exceptions import ProfileNotFound

router = APIRouter(prefix="/sessions", tags=["sessions"])


class CreateSessionRequest(BaseModel):
    profile_id: str


@router.post("", status_code=201)
async def create_session(
    body: CreateSessionRequest,
    store: Annotated[SessionStore, Depends(get_session_store)],
    profiles: Annotated[ProfileRegistry, Depends(get_profile_registry)],
) -> dict:
    try:
        profiles.get(body.profile_id)
    except ProfileNotFound:
        raise HTTPException(status_code=404, detail=f"Profile '{body.profile_id}' not found")

    session = await store.create(body.profile_id)
    return {
        "session_id": session.id,
        "profile_id": session.profile_id,
        "created_at": session.created_at.isoformat(),
    }


@router.get("")
async def list_sessions(
    store: Annotated[SessionStore, Depends(get_session_store)],
) -> list[dict]:
    sessions = await store.list_all()
    return [
        {
            "session_id": s.id,
            "profile_id": s.profile_id,
            "message_count": len(s.messages),
            "created_at": s.created_at.isoformat(),
            "last_active": s.last_active.isoformat(),
        }
        for s in sessions
    ]


@router.get("/{session_id}")
async def get_session(
    session_id: str,
    store: Annotated[SessionStore, Depends(get_session_store)],
) -> dict:
    session = await store.get(session_id)
    if session is None:
        raise HTTPException(status_code=404, detail="Session not found")
    return {
        "session_id": session.id,
        "profile_id": session.profile_id,
        "messages": [m.model_dump(exclude_none=True) for m in session.messages],
        "created_at": session.created_at.isoformat(),
        "last_active": session.last_active.isoformat(),
    }


@router.delete("/{session_id}", status_code=204)
async def delete_session(
    session_id: str,
    store: Annotated[SessionStore, Depends(get_session_store)],
) -> None:
    deleted = await store.delete(session_id)
    if not deleted:
        raise HTTPException(status_code=404, detail="Session not found")