Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/app/endpoints/rlsapi_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,11 @@ def _get_default_model_id() -> str:
if configuration.inference is None:
msg = "No inference configuration available"
logger.error(msg)
raise HTTPException(
status_code=503,
detail={"response": "Service configuration error", "cause": msg},
error_response = ServiceUnavailableResponse(
backend_name="inference service (configuration)",
cause=msg,
)
raise HTTPException(**error_response.model_dump())

model_id = configuration.inference.default_model
provider_id = configuration.inference.default_provider
Expand All @@ -146,10 +147,11 @@ def _get_default_model_id() -> str:

msg = "No default model configured for rlsapi v1 inference"
logger.error(msg)
raise HTTPException(
status_code=503,
detail={"response": "Service configuration error", "cause": msg},
error_response = ServiceUnavailableResponse(
backend_name="inference service (configuration)",
cause=msg,
)
raise HTTPException(**error_response.model_dump())


async def retrieve_simple_response(
Expand Down
42 changes: 38 additions & 4 deletions tests/unit/app/endpoints/test_rlsapi_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
RlsapiV1SystemInfo,
RlsapiV1Terminal,
)
from models.responses import ServiceUnavailableResponse
from models.rlsapi.responses import RlsapiV1InferResponse
from tests.unit.utils.auth_helpers import mock_authorization_resolvers
from utils.suid import check_suid
Expand Down Expand Up @@ -235,7 +236,7 @@ def test_get_default_model_id_success(mock_configuration: AppConfig) -> None:


@pytest.mark.parametrize(
("config_setup", "expected_message"),
("config_setup", "expected_cause"),
[
pytest.param(
"missing_model",
Expand All @@ -253,9 +254,9 @@ def test_get_default_model_id_errors(
mocker: MockerFixture,
minimal_config: AppConfig,
config_setup: str,
expected_message: str,
expected_cause: str,
) -> None:
"""Test _get_default_model_id raises HTTPException for invalid configs."""
"""Test _get_default_model_id raises HTTPException with ServiceUnavailableResponse shape."""
if config_setup == "missing_model":
# Config exists but no model/provider defaults
mocker.patch("app.endpoints.rlsapi_v1.configuration", minimal_config)
Expand All @@ -269,7 +270,40 @@ def test_get_default_model_id_errors(
_get_default_model_id()

assert exc_info.value.status_code == 503
assert expected_message in str(exc_info.value.detail)
assert expected_cause in str(exc_info.value.detail)
# Verify ServiceUnavailableResponse produces dict with response+cause keys
detail: dict[str, str] = exc_info.value.detail # type: ignore[assignment]
assert set(detail.keys()) == {"response", "cause"}


def test_config_error_503_matches_llm_error_503_shape(
mocker: MockerFixture,
) -> None:
"""Test that configuration error 503s have the same shape as LLM error 503s.

Both _get_default_model_id() configuration errors and APIConnectionError
handlers use ServiceUnavailableResponse, producing identical detail shapes
with 'response' and 'cause' keys.
"""
# Trigger a configuration error 503
mock_config = mocker.Mock()
mock_config.inference = None
mocker.patch("app.endpoints.rlsapi_v1.configuration", mock_config)

with pytest.raises(HTTPException) as config_exc:
_get_default_model_id()

# Build an LLM connection error 503 using the same response model
llm_response = ServiceUnavailableResponse(
backend_name="Llama Stack",
cause="Unable to connect to the inference backend",
)
llm_detail = llm_response.model_dump()["detail"]

config_detail: dict[str, str] = config_exc.value.detail # type: ignore[assignment]

# Both must have identical key sets: {"response", "cause"}
assert set(config_detail.keys()) == set(llm_detail.keys()) == {"response", "cause"}


# --- Test retrieve_simple_response ---
Expand Down
Loading