"""会话持久化 API:/v1/xtc/sessions - POST /v1/xtc/sessions 创建会话 - GET /v1/xtc/sessions 列出我的会话 - GET /v1/xtc/sessions/{id} 获取会话详情 - PUT /v1/xtc/sessions/{id} 更新(标题) - DELETE /v1/xtc/sessions/{id} 删除 - POST /v1/xtc/sessions/{id}/messages 追加消息 - GET /v1/xtc/sessions/{id}/messages 列出消息 """ from __future__ import annotations from typing import Optional from fastapi import APIRouter, Body, Depends, Query, Request from ..auth import require_access_key from ..errors import HttpError from ..services import session_store from ._common import ok_with_cors router = APIRouter(prefix="/v1/xtc/sessions", tags=["sessions"]) @router.post("") async def create_session( body: dict = Body(default={}), access_key: str = Depends(require_access_key), ): sess = session_store.create_session( access_key=access_key, title=body.get("title"), provider=body.get("provider"), model=body.get("model"), ) return ok_with_cors({"session": sess}) @router.get("") async def list_sessions( access_key: str = Depends(require_access_key), limit: int = Query(default=50, ge=1, le=200), offset: int = Query(default=0, ge=0), ): items = session_store.list_sessions(access_key=access_key, limit=limit, offset=offset) return ok_with_cors({"items": items, "count": len(items)}) @router.get("/{session_id}") async def get_session( session_id: str, access_key: str = Depends(require_access_key), ): sess = session_store.get_session(session_id, access_key=access_key) if not sess: raise HttpError(f"session not found: {session_id}", status=404, code="not_found") return ok_with_cors({"session": sess}) @router.put("/{session_id}") async def update_session( session_id: str, body: dict = Body(default={}), access_key: str = Depends(require_access_key), ): sess = session_store.update_session( session_id, title=body.get("title"), access_key=access_key ) if not sess: raise HttpError(f"session not found: {session_id}", status=404, code="not_found") return ok_with_cors({"session": sess}) @router.delete("/{session_id}") async def delete_session( session_id: str, access_key: str = Depends(require_access_key), ): ok = session_store.delete_session(session_id, access_key=access_key) if not ok: raise HttpError(f"session not found: {session_id}", status=404, code="not_found") return ok_with_cors({"deleted": True, "id": session_id}) @router.post("/{session_id}/messages") async def append_message( session_id: str, body: dict = Body(default={}), access_key: str = Depends(require_access_key), ): if not session_store.get_session(session_id, access_key=access_key): raise HttpError(f"session not found: {session_id}", status=404, code="not_found") role = body.get("role") or "user" if role not in ("user", "assistant", "system"): raise HttpError("role must be user/assistant/system", status=400, code="bad_request") content = body.get("content") if content is None: raise HttpError("content is required", status=400, code="bad_request") msg = session_store.append_message( session_id=session_id, role=role, content=str(content), thought=body.get("thought"), provider=body.get("provider"), model=body.get("model"), file_keys=body.get("file_keys"), ) return ok_with_cors({"message": msg}) @router.get("/{session_id}/messages") async def list_messages( session_id: str, access_key: str = Depends(require_access_key), ): if not session_store.get_session(session_id, access_key=access_key): raise HttpError(f"session not found: {session_id}", status=404, code="not_found") msgs = session_store.list_messages(session_id) return ok_with_cors({"messages": msgs or [], "count": len(msgs or [])})