Hide LLM gateway URL from user-facing error messages

Replace endpoint URLs in httpx retry exhaustion errors with the branded
Alias Robotics® LLM servers label; URLs remain in debug logs only.
This commit is contained in:
Rufino Cabrera 2026-06-11 12:14:09 +02:00
parent f454c41e94
commit 23739d0631
2 changed files with 44 additions and 11 deletions

View File

@ -43,6 +43,9 @@ _MAX_DELAY = 30.0 # cap in seconds
# HTTP status codes that trigger automatic retry
_RETRYABLE_STATUS = {429, 502, 503, 504, 529}
# User-facing label — never embed gateway URLs in exception text shown in the REPL.
_LLM_SERVER_LABEL = "Alias Robotics® LLM servers"
_LOG = logging.getLogger(__name__)
@ -197,11 +200,17 @@ async def direct_httpx_completion(
# Retries exhausted — raise typed error
if resp.status_code == 429:
raise LLMRateLimited(
f"Rate limited (429) after {_MAX_RETRIES} retries from {url}",
(
f"Rate limited (429) after {_MAX_RETRIES} retries "
f"from {_LLM_SERVER_LABEL}"
),
retry_after=_extract_retry_after(resp),
)
raise LLMProviderUnavailable(
f"Server error ({resp.status_code}) after {_MAX_RETRIES} retries from {url}"
(
f"Server error ({resp.status_code}) after "
f"{_MAX_RETRIES} retries from {_LLM_SERVER_LABEL}"
)
)
# HTTP 413: request body exceeds gateway/proxy POST
@ -215,7 +224,7 @@ async def direct_httpx_completion(
pass
_log_failed_completion_response(resp, url)
raise LLMContextOverflow(
f"Request body too large (413) for {url}",
f"Request body too large (413) for {_LLM_SERVER_LABEL}",
details=_build_413_details(url, body),
)
@ -312,11 +321,11 @@ async def direct_httpx_completion(
continue
if e.response.status_code == 429:
raise LLMRateLimited(
f"Rate limited (429) after retries from {url}"
f"Rate limited (429) after retries from {_LLM_SERVER_LABEL}"
) from e
if e.response.status_code in (408, 504):
raise LLMTimeout(
f"Timeout ({e.response.status_code}) from {url}"
f"Timeout ({e.response.status_code}) from {_LLM_SERVER_LABEL}"
) from e
raise
@ -368,19 +377,28 @@ async def direct_httpx_completion(
# Retries exhausted — raise typed error
if resp.status_code == 429:
raise LLMRateLimited(
f"Rate limited (429) after {_MAX_RETRIES} retries from {url}",
(
f"Rate limited (429) after {_MAX_RETRIES} retries "
f"from {_LLM_SERVER_LABEL}"
),
retry_after=_extract_retry_after(resp),
)
if resp.status_code in (408, 504):
raise LLMTimeout(
f"Timeout ({resp.status_code}) after {_MAX_RETRIES} retries from {url}"
(
f"Timeout ({resp.status_code}) after {_MAX_RETRIES} "
f"retries from {_LLM_SERVER_LABEL}"
)
)
raise LLMProviderUnavailable(
f"Server error ({resp.status_code}) after {_MAX_RETRIES} retries from {url}"
(
f"Server error ({resp.status_code}) after "
f"{_MAX_RETRIES} retries from {_LLM_SERVER_LABEL}"
)
)
if resp.status_code in (408,):
raise LLMTimeout(f"Timeout ({resp.status_code}) from {url}")
raise LLMTimeout(f"Timeout ({resp.status_code}) from {_LLM_SERVER_LABEL}")
# HTTP 413: request body exceeds gateway/proxy POST size cap.
# Not in _RETRYABLE_STATUS because resending the same body
@ -390,7 +408,7 @@ async def direct_httpx_completion(
if resp.status_code == 413:
_log_failed_completion_response(resp, url)
raise LLMContextOverflow(
f"Request body too large (413) for {url}",
f"Request body too large (413) for {_LLM_SERVER_LABEL}",
details=_build_413_details(url, body),
)
@ -422,4 +440,4 @@ async def direct_httpx_completion(
# Should not reach here
if last_error:
raise last_error
raise LLMProviderUnavailable(f"All retries exhausted for {url}")
raise LLMProviderUnavailable(f"All retries exhausted for {_LLM_SERVER_LABEL}")

View File

@ -0,0 +1,15 @@
"""Regression: LLM error messages must not expose gateway URLs in the REPL."""
from __future__ import annotations
class TestLlmErrorMessagesHideGatewayUrl:
def test_user_facing_messages_use_branded_server_label(self):
from cai.sdk.agents.models.chatcompletions import httpx_client
import inspect
source = inspect.getsource(httpx_client)
assert "_LLM_SERVER_LABEL" in source
assert httpx_client._LLM_SERVER_LABEL == "Alias Robotics® LLM servers"
assert "retries from {url}" not in source
assert "All retries exhausted for {url}" not in source