Some checks failed
verify / verify (push) Has been cancelled
The API and ingestion tools now use a fixed internal model gateway while governed profiles, embedding cache assignments, traceable citations, and stable API errors establish the boundaries required by later workflows. Constraint: The current Alibaba Cloud workspace rejects all three live model calls with authentication failures Rejected: Give the API or seed tools the Bailian key and direct egress | combines database access, cloud credentials, and public network access Rejected: Mix offline and Bailian vectors in one demo namespace | makes profile activation and retrieval ambiguous Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep Bailian credentials and egress exclusive to model-gateway and create a new immutable profile hash for any embedding identity change Tested: make verify; 121 backend tests; 14 frontend tests; fresh and populated Alembic upgrade-downgrade-upgrade; two idempotent offline seeds; Docker health and HTTP retrieval; isolated provider smoke Not-tested: Successful live Bailian responses because the supplied workspace credential currently fails authentication
63 lines
1.6 KiB
Python
63 lines
1.6 KiB
Python
"""Stable RFC 9457-style problem responses for public API failures."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
from fastapi import Request
|
|
from fastapi.responses import JSONResponse
|
|
|
|
PROBLEM_MEDIA_TYPE = "application/problem+json"
|
|
PROBLEM_BASE = "https://geological-rag.local/problems"
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class ApiProblem(Exception):
|
|
"""An intentionally public and sanitized application failure."""
|
|
|
|
status: int
|
|
code: str
|
|
title: str
|
|
detail: str
|
|
|
|
def __post_init__(self) -> None:
|
|
Exception.__init__(self, self.code)
|
|
|
|
|
|
def problem_payload(
|
|
*,
|
|
status: int,
|
|
code: str,
|
|
title: str,
|
|
detail: str,
|
|
trace_id: str,
|
|
field_errors: list[dict[str, Any]] | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Build the only public error envelope used by formal product routes."""
|
|
|
|
return {
|
|
"type": f"{PROBLEM_BASE}/{code.lower().replace('_', '-')}",
|
|
"title": title,
|
|
"status": status,
|
|
"code": code,
|
|
"detail": detail,
|
|
"trace_id": trace_id,
|
|
"field_errors": field_errors or [],
|
|
}
|
|
|
|
|
|
def api_problem_handler(request: Request, exc: ApiProblem) -> JSONResponse:
|
|
trace_id = str(getattr(request.state, "trace_id", "unavailable"))
|
|
return JSONResponse(
|
|
status_code=exc.status,
|
|
media_type=PROBLEM_MEDIA_TYPE,
|
|
content=problem_payload(
|
|
status=exc.status,
|
|
code=exc.code,
|
|
title=exc.title,
|
|
detail=exc.detail,
|
|
trace_id=trace_id,
|
|
),
|
|
)
|