Refactor DeepSeek V4 reasoning helper imports

This commit is contained in:
cdxiaodong 2026-04-29 10:23:57 +08:00
parent a3dbffa8e7
commit 5dd872eb12
5 changed files with 52 additions and 39 deletions

View file

@ -56,7 +56,7 @@ from litellm.types.utils import (
from litellm.utils import convert_to_model_response_object
from ..common_utils import OpenAIError
from ..common_utils import patch_deepseek_v4_reasoning_messages
from ..deepseek_reasoning_utils import patch_deepseek_v4_reasoning_messages
if TYPE_CHECKING:
from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj

View file

@ -258,43 +258,6 @@ class BaseOpenAILLM:
class OpenAICredentials(NamedTuple):
api_base: str
api_key: Optional[str]
def requires_deepseek_v4_reasoning_content(model: Optional[str]) -> bool:
"""Return True when the model requires DeepSeek V4 thinking history."""
if not model:
return False
normalized_model = model.lower()
if normalized_model.startswith("responses/"):
normalized_model = normalized_model.split("responses/", 1)[1]
return "deepseek-v4" in normalized_model
def patch_deepseek_v4_reasoning_messages(
model: Optional[str], messages: List[Any]
) -> List[Any]:
"""
Ensure assistant tool-call messages include reasoning_content for DeepSeek V4.
DeepSeek V4 rejects multi-turn requests when prior assistant tool-call messages
omit the reasoning_content field, even if the value is empty.
"""
if not requires_deepseek_v4_reasoning_content(model):
return messages
for message in messages:
if not isinstance(message, dict):
continue
if message.get("role") != "assistant":
continue
if not (message.get("tool_calls") or message.get("tool_call_id")):
continue
if message.get("reasoning_content") is None:
message["reasoning_content"] = ""
return messages
organization: Optional[str]

View file

@ -0,0 +1,38 @@
from typing import Any, List, Optional
def requires_deepseek_v4_reasoning_content(model: Optional[str]) -> bool:
"""Return True when the model requires DeepSeek V4 thinking history."""
if not model:
return False
normalized_model = model.lower()
if normalized_model.startswith("responses/"):
normalized_model = normalized_model.split("responses/", 1)[1]
return "deepseek-v4" in normalized_model
def patch_deepseek_v4_reasoning_messages(
model: Optional[str], messages: List[Any]
) -> List[Any]:
"""
Ensure assistant tool-call messages include reasoning_content for DeepSeek V4.
DeepSeek V4 rejects multi-turn requests when prior assistant tool-call messages
omit the reasoning_content field, even if the value is empty.
"""
if not requires_deepseek_v4_reasoning_content(model):
return messages
for message in messages:
if not isinstance(message, dict):
continue
if message.get("role") != "assistant":
continue
if not (message.get("tool_calls") or message.get("tool_call_id")):
continue
if message.get("reasoning_content") is None:
message["reasoning_content"] = ""
return messages

View file

@ -58,9 +58,9 @@ from .chat.o_series_transformation import OpenAIOSeriesConfig
from .common_utils import (
BaseOpenAILLM,
OpenAIError,
patch_deepseek_v4_reasoning_messages,
drop_params_from_unprocessable_entity_error,
)
from .deepseek_reasoning_utils import patch_deepseek_v4_reasoning_messages
openaiOSeriesConfig = OpenAIOSeriesConfig()
openAIGPT5Config = OpenAIGPT5Config()

View file

@ -241,3 +241,15 @@ def test_deepseek_reasoner_transform_request_does_not_inject_reasoning_content()
)
assert "reasoning_content" not in request["messages"][1]
def test_get_openai_credentials_preserves_organization_field():
from litellm.llms.openai.common_utils import get_openai_credentials
credentials = get_openai_credentials(
api_base="https://example.com/v1",
api_key="test-key",
organization="test-org",
)
assert credentials.organization == "test-org"