"""Actor-private messaging APIs; the Agent verifies its session ownership.""" from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query from psycopg import AsyncConnection from app.auth.permissions import OPERATIONAL_TASK_VIEW, OPERATIONAL_TASK_WRITE, require_permission from app.auth.project_dependencies import ProjectContext, get_project_pg_connection from app.domain.domain_errors import DomainError from app.domain.schemas.agent_messages import ( AgentMessage, AgentMessageCreate, AgentMessageDelivery, AgentMessagePage, AgentMessageReply, ) from app.infra.db.postgresql.agent_messages import AgentMessageRepository from app.services.agent_messages import AgentMessageService router = APIRouter(prefix="/agent-messages") def _service(ctx: ProjectContext, conn: AsyncConnection) -> AgentMessageService: return AgentMessageService(AgentMessageRepository(conn, ctx.project_id), ctx) def _raise_domain(exc: DomainError): raise HTTPException(status_code=exc.status, detail=exc.payload()) from exc @router.post("", response_model=AgentMessage, status_code=201) async def create_agent_message( command: AgentMessageCreate, ctx: ProjectContext = Depends(require_permission(OPERATIONAL_TASK_WRITE)), conn: AsyncConnection = Depends(get_project_pg_connection), ): try: return await _service(ctx, conn).create(command) except DomainError as exc: _raise_domain(exc) @router.get("", response_model=AgentMessagePage) async def list_agent_messages( session_id: str = Query(min_length=1, max_length=500), limit: int = Query(default=50, ge=1, le=100), cursor: str | None = None, pending_only: bool = False, ctx: ProjectContext = Depends(require_permission(OPERATIONAL_TASK_VIEW)), conn: AsyncConnection = Depends(get_project_pg_connection), ): try: return await _service(ctx, conn).list_session(session_id, limit, cursor, pending_only) except DomainError as exc: _raise_domain(exc) @router.get("/pending", response_model=AgentMessagePage) async def list_pending_agent_messages( limit: int = Query(default=50, ge=1, le=100), cursor: str | None = None, ctx: ProjectContext = Depends(require_permission(OPERATIONAL_TASK_VIEW)), conn: AsyncConnection = Depends(get_project_pg_connection), ): try: return await _service(ctx, conn).pending(limit, cursor) except DomainError as exc: _raise_domain(exc) @router.get("/{message_id}", response_model=AgentMessage) async def get_agent_message( message_id: UUID, ctx: ProjectContext = Depends(require_permission(OPERATIONAL_TASK_VIEW)), conn: AsyncConnection = Depends(get_project_pg_connection), ): try: return await _service(ctx, conn).get(message_id) except DomainError as exc: _raise_domain(exc) @router.post("/{message_id}/reply", response_model=AgentMessage, status_code=201) async def reply_agent_message( message_id: UUID, command: AgentMessageReply, ctx: ProjectContext = Depends(require_permission(OPERATIONAL_TASK_WRITE)), conn: AsyncConnection = Depends(get_project_pg_connection), ): try: return await _service(ctx, conn).reply(message_id, command) except DomainError as exc: _raise_domain(exc) @router.post("/{message_id}/delivery", response_model=AgentMessage) async def record_agent_message_delivery( message_id: UUID, command: AgentMessageDelivery, ctx: ProjectContext = Depends(require_permission(OPERATIONAL_TASK_VIEW)), conn: AsyncConnection = Depends(get_project_pg_connection), ): try: return await _service(ctx, conn).delivery(message_id, command) except DomainError as exc: _raise_domain(exc)