mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
Merge e12ab58d13 into cdb60af024
This commit is contained in:
commit
2d9a6682eb
2 changed files with 103 additions and 8 deletions
|
|
@ -649,7 +649,7 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM):
|
|||
if custom_llm_provider is not None and custom_llm_provider != "openai":
|
||||
model_response.model = f"{custom_llm_provider}/{model}"
|
||||
|
||||
for _ in range(2): # if call fails due to alternating messages, retry with reformatted message
|
||||
for attempt in range(2): # if call fails due to alternating messages, retry with reformatted message
|
||||
try:
|
||||
max_retries = inference_params.pop("max_retries", 2)
|
||||
if acompletion is True:
|
||||
|
|
@ -778,11 +778,10 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM):
|
|||
return final_response_obj
|
||||
except openai.UnprocessableEntityError as e:
|
||||
## check if body contains unprocessable params - related issue https://github.com/BerriAI/litellm/issues/4800
|
||||
if litellm.drop_params is True or drop_params is True:
|
||||
if attempt == 0 and (litellm.drop_params is True or drop_params is True):
|
||||
inference_params = drop_params_from_unprocessable_entity_error(e, inference_params)
|
||||
else:
|
||||
raise e
|
||||
# e.message
|
||||
except Exception as e:
|
||||
if print_verbose is not None:
|
||||
print_verbose(f"openai.py: Received openai error - {e}")
|
||||
|
|
@ -858,7 +857,7 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM):
|
|||
litellm_params=litellm_params,
|
||||
headers=headers or {},
|
||||
)
|
||||
for _ in range(2): # if call fails due to alternating messages, retry with reformatted message
|
||||
for attempt in range(2): # if call fails due to alternating messages, retry with reformatted message
|
||||
try:
|
||||
openai_aclient: AsyncOpenAI = self._get_openai_client(
|
||||
is_async=True,
|
||||
|
|
@ -930,11 +929,10 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM):
|
|||
return final_response_obj
|
||||
except openai.UnprocessableEntityError as e:
|
||||
## check if body contains unprocessable params - related issue https://github.com/BerriAI/litellm/issues/4800
|
||||
if litellm.drop_params is True or drop_params is True:
|
||||
if attempt == 0 and (litellm.drop_params is True or drop_params is True):
|
||||
data = drop_params_from_unprocessable_entity_error(e, data)
|
||||
else:
|
||||
raise e
|
||||
# e.message
|
||||
except Exception as e:
|
||||
exception_response = getattr(e, "response", None)
|
||||
status_code = getattr(e, "status_code", 500)
|
||||
|
|
@ -1038,7 +1036,7 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM):
|
|||
)
|
||||
data["stream"] = True
|
||||
data.update(self.get_stream_options(stream_options=stream_options, api_base=api_base))
|
||||
for _ in range(2):
|
||||
for attempt in range(2):
|
||||
try:
|
||||
openai_aclient: AsyncOpenAI = self._get_openai_client(
|
||||
is_async=True,
|
||||
|
|
@ -1081,7 +1079,7 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM):
|
|||
return streamwrapper
|
||||
except openai.UnprocessableEntityError as e:
|
||||
## check if body contains unprocessable params - related issue https://github.com/BerriAI/litellm/issues/4800
|
||||
if litellm.drop_params is True or drop_params is True:
|
||||
if attempt == 0 and (litellm.drop_params is True or drop_params is True):
|
||||
data = drop_params_from_unprocessable_entity_error(e, data)
|
||||
else:
|
||||
raise e
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
"""
|
||||
Regression tests for issue #32221: with drop_params=True, two consecutive 422s
|
||||
with an unstructured body must raise instead of silently returning None.
|
||||
"""
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import httpx
|
||||
import openai
|
||||
import pytest
|
||||
|
||||
from litellm.llms.openai.common_utils import OpenAIError
|
||||
from litellm.llms.openai.openai import OpenAIChatCompletion, OpenAIConfig
|
||||
from litellm.types.utils import ModelResponse
|
||||
|
||||
|
||||
def _unstructured_422_error() -> openai.UnprocessableEntityError:
|
||||
return openai.UnprocessableEntityError(
|
||||
message="Error code: 422 - content moderation rejected the request",
|
||||
response=httpx.Response(
|
||||
422,
|
||||
request=httpx.Request("POST", "https://api.openai.com/v1/chat/completions"),
|
||||
json={"error": {"message": "content moderation rejected the request"}},
|
||||
),
|
||||
body={"message": "content moderation rejected the request"},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_acompletion_raises_after_unstructured_422_retry_exhaustion():
|
||||
mock_client = MagicMock()
|
||||
mock_client.chat.completions.with_raw_response.create = AsyncMock(side_effect=_unstructured_422_error())
|
||||
|
||||
with pytest.raises((openai.UnprocessableEntityError, OpenAIError)) as exc_info:
|
||||
await OpenAIChatCompletion().acompletion(
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
provider_config=OpenAIConfig(),
|
||||
model="gpt-4o",
|
||||
model_response=ModelResponse(),
|
||||
logging_obj=MagicMock(),
|
||||
timeout=30.0,
|
||||
api_key="sk-test",
|
||||
client=mock_client,
|
||||
drop_params=True,
|
||||
)
|
||||
|
||||
assert exc_info.value.status_code == 422
|
||||
assert mock_client.chat.completions.with_raw_response.create.await_count == 2
|
||||
|
||||
|
||||
def test_completion_raises_after_unstructured_422_retry_exhaustion():
|
||||
mock_client = MagicMock(spec=openai.OpenAI)
|
||||
mock_client.api_key = "sk-test"
|
||||
mock_client._base_url = MagicMock()
|
||||
mock_client.chat.completions.with_raw_response.create.side_effect = _unstructured_422_error()
|
||||
|
||||
with pytest.raises((openai.UnprocessableEntityError, OpenAIError)) as exc_info:
|
||||
OpenAIChatCompletion().completion(
|
||||
model_response=ModelResponse(),
|
||||
timeout=30.0,
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
logging_obj=MagicMock(),
|
||||
model="gpt-4o",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
api_key="sk-test",
|
||||
client=mock_client,
|
||||
drop_params=True,
|
||||
)
|
||||
|
||||
assert exc_info.value.status_code == 422
|
||||
assert mock_client.chat.completions.with_raw_response.create.call_count == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_async_streaming_raises_after_unstructured_422_retry_exhaustion():
|
||||
mock_client = MagicMock()
|
||||
mock_client.chat.completions.with_raw_response.create = AsyncMock(side_effect=_unstructured_422_error())
|
||||
|
||||
with pytest.raises((openai.UnprocessableEntityError, OpenAIError)) as exc_info:
|
||||
await OpenAIChatCompletion().async_streaming(
|
||||
timeout=30.0,
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
provider_config=OpenAIConfig(),
|
||||
model="gpt-4o",
|
||||
logging_obj=MagicMock(),
|
||||
api_key="sk-test",
|
||||
client=mock_client,
|
||||
drop_params=True,
|
||||
)
|
||||
|
||||
assert exc_info.value.status_code == 422
|
||||
assert mock_client.chat.completions.with_raw_response.create.await_count == 2
|
||||
Loading…
Add table
Reference in a new issue