"""聊天 API。""" from fastapi import APIRouter, Depends, Header, Query, Request, Response, status from app.api.v1.deps import get_current_user from app.schemas.auth import CurrentUser from app.schemas.chat import ( ChatMessageListResponse, ChatMessageResponse, ChatSessionListResponse, ChatSessionResponse, CreateSessionRequest, SelectVersionRequest, SendMessageRequest, SendMessageResponse, UpdateSessionRequest, ) from app.services.chat import ( create_session, delete_session, get_session_response, list_message_responses, list_session_responses, select_message_version, send_message, update_session_response, ) from app.services.idempotency import run_idempotent router = APIRouter(prefix="/chat", tags=["chat"]) @router.post("/sessions", response_model=ChatSessionResponse) async def create_chat_session( payload: CreateSessionRequest, current_user: CurrentUser = Depends(get_current_user), ) -> ChatSessionResponse: return await create_session(payload, owner_scope=current_user.owner_scope) @router.get("/sessions", response_model=ChatSessionListResponse) async def list_chat_sessions( current_user: CurrentUser = Depends(get_current_user), status: str | None = Query(default=None, description="按状态过滤:active / archived"), limit: int = Query(default=50, ge=1, le=100), offset: int = Query(default=0, ge=0), ) -> ChatSessionListResponse: return await list_session_responses( owner_scope=current_user.owner_scope, status=status, limit=limit, offset=offset ) @router.get("/sessions/{session_id}", response_model=ChatSessionResponse) async def get_chat_session( session_id: str, current_user: CurrentUser = Depends(get_current_user), ) -> ChatSessionResponse: return await get_session_response(session_id, owner_scope=current_user.owner_scope) @router.patch("/sessions/{session_id}", response_model=ChatSessionResponse) async def update_chat_session( session_id: str, payload: UpdateSessionRequest, current_user: CurrentUser = Depends(get_current_user), ) -> ChatSessionResponse: return await update_session_response(session_id, payload, owner_scope=current_user.owner_scope) @router.delete("/sessions/{session_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_chat_session( session_id: str, current_user: CurrentUser = Depends(get_current_user), ) -> Response: await delete_session(session_id, owner_scope=current_user.owner_scope) return Response(status_code=status.HTTP_204_NO_CONTENT) @router.post("/sessions/{session_id}/messages", response_model=SendMessageResponse) async def send_chat_message( session_id: str, payload: SendMessageRequest, request: Request, idempotency_key: str | None = Header(default=None, alias="Idempotency-Key"), current_user: CurrentUser = Depends(get_current_user), ) -> SendMessageResponse: return await run_idempotent( key=idempotency_key, method="POST", path=str(request.url.path), payload=payload, response_type=SendMessageResponse, resource_type="run", handler=lambda session: send_message( session, session_id, payload, owner_scope=current_user.owner_scope, tool_runtime=getattr(request.app.state, "tool_runtime", None), confirmation_registry=getattr(request.app.state, "confirmation_registry", None), confirmation_store=getattr(request.app.state, "confirmation_store", None), event_store=getattr(request.app.state, "event_store", None), agent_run_registry=getattr(request.app.state, "agent_run_registry", None), python_skill_catalog=getattr(request.app.state, "python_skill_catalog", None), ), ) @router.get("/sessions/{session_id}/messages", response_model=ChatMessageListResponse) async def list_chat_messages( session_id: str, current_user: CurrentUser = Depends(get_current_user), limit: int = Query(default=100, ge=1, le=200), offset: int = Query(default=0, ge=0), ) -> ChatMessageListResponse: return await list_message_responses( session_id, owner_scope=current_user.owner_scope, limit=limit, offset=offset ) @router.patch( "/sessions/{session_id}/messages/{message_id}/version", response_model=ChatMessageResponse, ) async def select_message_version_endpoint( session_id: str, message_id: str, payload: SelectVersionRequest, current_user: CurrentUser = Depends(get_current_user), ) -> ChatMessageResponse: """选择/激活消息的某个历史版本。""" return await select_message_version( session_id, message_id, payload, owner_scope=current_user.owner_scope, )