feat: command palette, PSA ticket context, session-to-flow converter #108

Merged
chihlasm merged 27 commits from feat/command-palette-session-flow-psa-context into main 2026-03-16 17:39:17 +00:00
Showing only changes of commit c76bd54f1a - Show all commits

View File

@@ -319,6 +319,61 @@ async def search_tickets(
raise HTTPException(status_code=502, detail=str(e))
@router.get("/tickets/{ticket_id}/context")
async def get_ticket_context(
ticket_id: int,
current_user: Annotated[User, Depends(get_current_active_user)],
db: Annotated[AsyncSession, Depends(get_db)],
):
"""Get rich ticket context (company, contact, configs, notes, related tickets) for AI prompt injection."""
from app.services.psa.registry import get_provider_for_account
from app.services.psa.exceptions import (
PSAError,
PSAAuthError,
PSAPermissionError,
PSANotFoundError,
PSAConnectionError,
)
from app.schemas.psa_context import TicketContext
if not current_user.account_id:
raise HTTPException(status_code=400, detail="User has no account")
# Look up the active connection for connection_id
conn_result = await db.execute(
select(PsaConnection).where(
PsaConnection.account_id == current_user.account_id,
PsaConnection.is_active.is_(True),
)
)
connection = conn_result.scalar_one_or_none()
if not connection:
raise HTTPException(status_code=404, detail="No active PSA connection configured")
try:
provider = await get_provider_for_account(current_user.account_id, db)
except PSAConnectionError:
raise HTTPException(status_code=404, detail="No active PSA connection configured")
except PSAError as e:
raise HTTPException(status_code=502, detail=str(e))
try:
ctx: TicketContext = await provider.get_ticket_context(
ticket_id=ticket_id,
connection_id=str(connection.id),
)
return ctx
except (PSAAuthError, PSAPermissionError):
raise HTTPException(
status_code=502,
detail={"error": "psa_auth_failed", "message": "PSA credentials may have expired."},
)
except PSANotFoundError:
raise HTTPException(status_code=404, detail="Ticket not found")
except PSAError as e:
raise HTTPException(status_code=502, detail=str(e))
@router.get("/tickets/{ticket_id}")
async def get_ticket(
ticket_id: str,