chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from openai import APIConnectionError, APITimeoutError
|
||||
|
||||
from ..retry import ModelRetryAdvice, ModelRetryAdviceRequest, ModelRetryNormalizedError
|
||||
from ._retry_runtime import (
|
||||
get_error_code as _get_error_code,
|
||||
get_error_header as _get_header_value,
|
||||
get_request_id as _get_request_id,
|
||||
get_retry_after,
|
||||
get_status_code as _get_status_code,
|
||||
iter_error_chain as _iter_error_chain,
|
||||
)
|
||||
|
||||
|
||||
def _is_stateful_request(request: ModelRetryAdviceRequest) -> bool:
|
||||
return bool(request.previous_response_id or request.conversation_id)
|
||||
|
||||
|
||||
def _build_normalized_error(
|
||||
error: Exception,
|
||||
*,
|
||||
retry_after: float | None,
|
||||
) -> ModelRetryNormalizedError:
|
||||
return ModelRetryNormalizedError(
|
||||
status_code=_get_status_code(error),
|
||||
error_code=_get_error_code(error),
|
||||
message=str(error),
|
||||
request_id=_get_request_id(error),
|
||||
retry_after=retry_after,
|
||||
is_abort=False,
|
||||
is_network_error=any(
|
||||
isinstance(candidate, APIConnectionError) for candidate in _iter_error_chain(error)
|
||||
),
|
||||
is_timeout=any(
|
||||
isinstance(candidate, APITimeoutError) for candidate in _iter_error_chain(error)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def get_openai_retry_advice(request: ModelRetryAdviceRequest) -> ModelRetryAdvice | None:
|
||||
error = request.error
|
||||
if getattr(error, "unsafe_to_replay", False):
|
||||
return ModelRetryAdvice(
|
||||
suggested=False,
|
||||
replay_safety="unsafe",
|
||||
reason=str(error),
|
||||
)
|
||||
|
||||
error_message = str(error).lower()
|
||||
if (
|
||||
"the request may have been accepted, so the sdk will not automatically "
|
||||
"retry this websocket request." in error_message
|
||||
):
|
||||
return ModelRetryAdvice(
|
||||
suggested=False,
|
||||
replay_safety="unsafe",
|
||||
reason=str(error),
|
||||
)
|
||||
|
||||
retry_after = get_retry_after(error)
|
||||
|
||||
normalized = _build_normalized_error(error, retry_after=retry_after)
|
||||
stateful_request = _is_stateful_request(request)
|
||||
should_retry_header = _get_header_value(error, "x-should-retry")
|
||||
if should_retry_header is not None:
|
||||
header_value = should_retry_header.lower().strip()
|
||||
if header_value == "true":
|
||||
return ModelRetryAdvice(
|
||||
suggested=True,
|
||||
retry_after=retry_after,
|
||||
replay_safety="safe",
|
||||
reason=str(error),
|
||||
normalized=normalized,
|
||||
)
|
||||
if header_value == "false":
|
||||
return ModelRetryAdvice(
|
||||
suggested=False,
|
||||
retry_after=retry_after,
|
||||
reason=str(error),
|
||||
normalized=normalized,
|
||||
)
|
||||
|
||||
if normalized.is_network_error or normalized.is_timeout:
|
||||
return ModelRetryAdvice(
|
||||
suggested=True,
|
||||
retry_after=retry_after,
|
||||
reason=str(error),
|
||||
normalized=normalized,
|
||||
)
|
||||
|
||||
if normalized.status_code in {408, 409, 429} or (
|
||||
isinstance(normalized.status_code, int) and normalized.status_code >= 500
|
||||
):
|
||||
advice = ModelRetryAdvice(
|
||||
suggested=True,
|
||||
retry_after=retry_after,
|
||||
reason=str(error),
|
||||
normalized=normalized,
|
||||
)
|
||||
if stateful_request:
|
||||
advice.replay_safety = "safe"
|
||||
return advice
|
||||
|
||||
if retry_after is not None:
|
||||
return ModelRetryAdvice(
|
||||
retry_after=retry_after,
|
||||
reason=str(error),
|
||||
normalized=normalized,
|
||||
)
|
||||
|
||||
return None
|
||||
Reference in New Issue
Block a user