Isolate cloud model access before enabling product RAG workflows
Some checks failed
verify / verify (push) Has been cancelled
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
This commit is contained in:
62
backend/app/core/problems.py
Normal file
62
backend/app/core/problems.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""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,
|
||||
),
|
||||
)
|
||||
Reference in New Issue
Block a user