Spaces:
Sleeping
Sleeping
| """Shared API request validation and safe error logging.""" | |
| from typing import Any, Literal | |
| from fastapi import HTTPException | |
| from fastapi.responses import JSONResponse | |
| from loguru import logger | |
| from free_claude_code.application.errors import ApplicationError, InvalidRequestError | |
| from free_claude_code.config.settings import Settings | |
| from free_claude_code.core.anthropic import ( | |
| anthropic_error_payload, | |
| anthropic_error_type_for_failure, | |
| ) | |
| from free_claude_code.core.diagnostics import ( | |
| redacted_exception_traceback, | |
| safe_exception_message, | |
| ) | |
| from free_claude_code.core.openai_responses import ( | |
| openai_error_payload, | |
| openai_error_type_for_failure, | |
| ) | |
| WireApi = Literal["messages", "responses"] | |
| def require_non_empty_messages(messages: list[Any]) -> None: | |
| if not messages: | |
| raise InvalidRequestError("messages cannot be empty") | |
| def ordinary_application_error_response( | |
| error: ApplicationError, | |
| *, | |
| wire_api: WireApi, | |
| request_id: str, | |
| ) -> JSONResponse: | |
| """Serialize a deterministic application error without terminal headers.""" | |
| if wire_api == "responses": | |
| return JSONResponse( | |
| status_code=error.status_code, | |
| content=openai_error_payload( | |
| message=error.message, | |
| error_type=openai_error_type_for_failure(error.kind), | |
| ), | |
| ) | |
| return JSONResponse( | |
| status_code=error.status_code, | |
| content=anthropic_error_payload( | |
| error_type=anthropic_error_type_for_failure(error.kind), | |
| message=error.message, | |
| request_id=request_id, | |
| ), | |
| ) | |
| def http_status_for_unexpected_api_exception(_exc: BaseException) -> int: | |
| return 500 | |
| def log_unexpected_api_exception( | |
| settings: Settings, | |
| exc: BaseException, | |
| *, | |
| context: str, | |
| request_id: str | None = None, | |
| ) -> None: | |
| """Log API failures without echoing exception text unless opted in.""" | |
| if settings.log_api_error_tracebacks: | |
| if request_id is not None: | |
| logger.error( | |
| "{} request_id={}: {}", | |
| context, | |
| request_id, | |
| safe_exception_message(exc), | |
| ) | |
| else: | |
| logger.error("{}: {}", context, safe_exception_message(exc)) | |
| logger.error(redacted_exception_traceback(exc)) | |
| return | |
| if request_id is not None: | |
| logger.error( | |
| "{} request_id={} exc_type={}", | |
| context, | |
| request_id, | |
| type(exc).__name__, | |
| ) | |
| else: | |
| logger.error("{} exc_type={}", context, type(exc).__name__) | |
| def unexpected_http_exception( | |
| settings: Settings, exc: Exception, *, context: str | |
| ) -> HTTPException: | |
| log_unexpected_api_exception(settings, exc, context=context) | |
| return HTTPException( | |
| status_code=http_status_for_unexpected_api_exception(exc), | |
| detail=safe_exception_message(exc), | |
| ) | |