chore: initial snapshot for gitea/github upload

This commit is contained in:
Your Name
2026-03-26 16:04:46 +08:00
commit a699a1ac98
3497 changed files with 1586237 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
"""Anthropic error format utilities."""
from .exception_mapping_utils import (
ANTHROPIC_ERROR_TYPE_MAP,
AnthropicExceptionMapping,
)
from .exceptions import (
AnthropicErrorDetail,
AnthropicErrorResponse,
AnthropicErrorType,
)
__all__ = [
"AnthropicErrorType",
"AnthropicErrorDetail",
"AnthropicErrorResponse",
"ANTHROPIC_ERROR_TYPE_MAP",
"AnthropicExceptionMapping",
]

View File

@@ -0,0 +1,172 @@
"""
Utilities for mapping exceptions to Anthropic error format.
Similar to litellm/litellm_core_utils/exception_mapping_utils.py but for Anthropic response format.
"""
from litellm.litellm_core_utils.safe_json_loads import safe_json_loads
from typing import Dict, Optional
from .exceptions import AnthropicErrorResponse, AnthropicErrorType
# HTTP status code -> Anthropic error type
# Source: https://docs.anthropic.com/en/api/errors
ANTHROPIC_ERROR_TYPE_MAP: Dict[int, AnthropicErrorType] = {
400: "invalid_request_error",
401: "authentication_error",
403: "permission_error",
404: "not_found_error",
413: "request_too_large",
429: "rate_limit_error",
500: "api_error",
529: "overloaded_error",
}
class AnthropicExceptionMapping:
"""
Helper class for mapping exceptions to Anthropic error format.
Similar pattern to ExceptionCheckers in litellm_core_utils/exception_mapping_utils.py
"""
@staticmethod
def get_error_type(status_code: int) -> AnthropicErrorType:
"""Map HTTP status code to Anthropic error type."""
return ANTHROPIC_ERROR_TYPE_MAP.get(status_code, "api_error")
@staticmethod
def create_error_response(
status_code: int,
message: str,
request_id: Optional[str] = None,
) -> AnthropicErrorResponse:
"""
Create an Anthropic-formatted error response dict.
Anthropic error format:
{
"type": "error",
"error": {"type": "...", "message": "..."},
"request_id": "req_..."
}
"""
error_type = AnthropicExceptionMapping.get_error_type(status_code)
response: AnthropicErrorResponse = {
"type": "error",
"error": {
"type": error_type,
"message": message,
},
}
if request_id:
response["request_id"] = request_id
return response
@staticmethod
def extract_error_message(raw_message: str) -> str:
"""
Extract error message from various provider response formats.
Handles:
- Bedrock: {"detail": {"message": "..."}}
- AWS: {"Message": "..."}
- Generic: {"message": "..."}
- Plain strings
"""
parsed = safe_json_loads(raw_message)
if isinstance(parsed, dict):
# Bedrock format
if "detail" in parsed and isinstance(parsed["detail"], dict):
return parsed["detail"].get("message", raw_message)
# AWS/generic format
return parsed.get("Message") or parsed.get("message") or raw_message
return raw_message
@staticmethod
def _is_anthropic_error_dict(parsed: dict) -> bool:
"""
Check if a parsed dict is in Anthropic error format.
Anthropic error format:
{
"type": "error",
"error": {"type": "...", "message": "..."}
}
"""
return (
parsed.get("type") == "error"
and isinstance(parsed.get("error"), dict)
and "type" in parsed["error"]
and "message" in parsed["error"]
)
@staticmethod
def _extract_message_from_dict(parsed: dict, raw_message: str) -> str:
"""
Extract error message from a parsed provider-specific dict.
Handles:
- Bedrock: {"detail": {"message": "..."}}
- AWS: {"Message": "..."}
- Generic: {"message": "..."}
"""
# Bedrock format
if "detail" in parsed and isinstance(parsed["detail"], dict):
return parsed["detail"].get("message", raw_message)
# AWS/generic format
return parsed.get("Message") or parsed.get("message") or raw_message
@staticmethod
def transform_to_anthropic_error(
status_code: int,
raw_message: str,
request_id: Optional[str] = None,
) -> AnthropicErrorResponse:
"""
Transform an error message to Anthropic format.
- If already in Anthropic format: passthrough unchanged
- Otherwise: extract message and create Anthropic error
Parses JSON only once for efficiency.
Args:
status_code: HTTP status code
raw_message: Raw error message (may be JSON string or plain text)
request_id: Optional request ID to include
Returns:
AnthropicErrorResponse dict
"""
# Try to parse as JSON once
parsed: Optional[dict] = safe_json_loads(raw_message)
if not isinstance(parsed, dict):
parsed = None
# If parsed and already in Anthropic format - passthrough
if parsed is not None and AnthropicExceptionMapping._is_anthropic_error_dict(
parsed
):
# Optionally add request_id if provided and not present
if request_id and "request_id" not in parsed:
parsed["request_id"] = request_id
return parsed # type: ignore
# Extract message - use parsed dict if available, otherwise raw string
if parsed is not None:
message = AnthropicExceptionMapping._extract_message_from_dict(
parsed, raw_message
)
else:
message = raw_message
return AnthropicExceptionMapping.create_error_response(
status_code=status_code,
message=message,
request_id=request_id,
)

View File

@@ -0,0 +1,41 @@
"""Anthropic error format type definitions."""
from typing_extensions import Literal, Required, TypedDict
# Known Anthropic error types
# Source: https://docs.anthropic.com/en/api/errors
AnthropicErrorType = Literal[
"invalid_request_error",
"authentication_error",
"permission_error",
"not_found_error",
"request_too_large",
"rate_limit_error",
"api_error",
"overloaded_error",
]
class AnthropicErrorDetail(TypedDict):
"""Inner error detail in Anthropic format."""
type: AnthropicErrorType
message: str
class AnthropicErrorResponse(TypedDict, total=False):
"""
Anthropic-formatted error response.
Format:
{
"type": "error",
"error": {"type": "...", "message": "..."},
"request_id": "req_..." # optional
}
"""
type: Required[Literal["error"]]
error: Required[AnthropicErrorDetail]
request_id: str