Skip to content

Commit 1b6fb0f

Browse files
committed
Restrict DeepSeek reasoning inclusion to documented cases
1 parent 2de7412 commit 1b6fb0f

File tree

3 files changed

+88
-11
lines changed

3 files changed

+88
-11
lines changed

src/agents/extensions/models/litellm_model.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -442,17 +442,19 @@ def _should_include_reasoning_content(self, model_settings: ModelSettings) -> bo
442442
"""Determine whether to forward reasoning_content on assistant messages.
443443
444444
DeepSeek thinking mode requires reasoning_content to be present on messages with tool
445-
calls, otherwise the API returns a 400.
445+
calls, otherwise the API returns a 400. Restrict this to DeepSeek models to avoid
446+
regressions with other providers.
446447
"""
447448
model_name = str(self.model).lower()
448-
base_url = (self.base_url or "").lower()
449449

450-
if "deepseek" in model_name or "deepseek.com" in base_url:
451-
return True
450+
thinking_param_enabled = (
451+
isinstance(model_settings.extra_body, dict) and "thinking" in model_settings.extra_body
452+
) or (model_settings.extra_args and "thinking" in model_settings.extra_args)
452453

453-
if isinstance(model_settings.extra_body, dict) and "thinking" in model_settings.extra_body:
454+
if "deepseek-reasoner" in model_name or "deepseek-r1" in model_name:
454455
return True
455-
if model_settings.extra_args and "thinking" in model_settings.extra_args:
456+
457+
if "deepseek" in model_name and thinking_param_enabled:
456458
return True
457459

458460
return False

src/agents/models/openai_chatcompletions.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -343,14 +343,15 @@ async def _fetch_response(
343343
def _should_include_reasoning_content(self, model_settings: ModelSettings) -> bool:
344344
"""Determine whether to forward reasoning_content on assistant messages."""
345345
model_name = str(self.model).lower()
346-
base_url = str(getattr(self._client, "base_url", "") or "").lower()
347346

348-
if "deepseek" in model_name or "deepseek.com" in base_url:
349-
return True
347+
thinking_param_enabled = (
348+
isinstance(model_settings.extra_body, dict) and "thinking" in model_settings.extra_body
349+
) or (model_settings.extra_args and "thinking" in model_settings.extra_args)
350350

351-
if isinstance(model_settings.extra_body, dict) and "thinking" in model_settings.extra_body:
351+
if "deepseek-reasoner" in model_name or "deepseek-r1" in model_name:
352352
return True
353-
if model_settings.extra_args and "thinking" in model_settings.extra_args:
353+
354+
if "deepseek" in model_name and thinking_param_enabled:
354355
return True
355356

356357
return False

tests/test_reasoning_content.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,3 +461,77 @@ def __init__(self):
461461
)
462462

463463
assert getattr(spy_items_to_messages, "include_reasoning_content", False) is False
464+
465+
466+
@pytest.mark.allow_call_model_methods
467+
@pytest.mark.asyncio
468+
async def test_openai_chatcompletions_deepseek_chat_requires_thinking(monkeypatch) -> None:
469+
"""
470+
DeepSeek chat models only include reasoning when thinking parameter is explicitly set.
471+
"""
472+
473+
def spy_items_to_messages(
474+
items: Any, preserve_thinking_blocks: bool = False, include_reasoning_content: bool = False
475+
):
476+
spy_items_to_messages.include_reasoning_content = include_reasoning_content # type: ignore[attr-defined] # noqa: E501
477+
return []
478+
479+
monkeypatch.setattr(Converter, "items_to_messages", staticmethod(spy_items_to_messages))
480+
481+
class DummyCompletions:
482+
async def create(self, **kwargs):
483+
return ChatCompletion(
484+
id="resp-id",
485+
created=0,
486+
model="deepseek-chat",
487+
object="chat.completion",
488+
choices=[
489+
CompletionChoice(
490+
index=0,
491+
finish_reason="stop",
492+
message=ChatCompletionMessage(role="assistant", content="Hi"),
493+
)
494+
],
495+
usage=CompletionUsage(completion_tokens=1, prompt_tokens=1, total_tokens=2),
496+
)
497+
498+
class DummyChat:
499+
def __init__(self):
500+
self.completions = DummyCompletions()
501+
502+
class DummyClient:
503+
def __init__(self):
504+
self.chat = DummyChat()
505+
self.base_url = "https://api.deepseek.com"
506+
507+
model = OpenAIChatCompletionsModel("deepseek-chat", cast(AsyncOpenAI, DummyClient()))
508+
509+
# Without thinking -> should be False
510+
await model.get_response(
511+
system_instructions=None,
512+
input="",
513+
model_settings=ModelSettings(),
514+
tools=[],
515+
output_schema=None,
516+
handoffs=[],
517+
tracing=ModelTracing.DISABLED,
518+
previous_response_id=None,
519+
conversation_id=None,
520+
prompt=None,
521+
)
522+
assert getattr(spy_items_to_messages, "include_reasoning_content", False) is False
523+
524+
# With thinking -> should be True
525+
await model.get_response(
526+
system_instructions=None,
527+
input="",
528+
model_settings=ModelSettings(extra_body={"thinking": {"type": "enabled"}}),
529+
tools=[],
530+
output_schema=None,
531+
handoffs=[],
532+
tracing=ModelTracing.DISABLED,
533+
previous_response_id=None,
534+
conversation_id=None,
535+
prompt=None,
536+
)
537+
assert getattr(spy_items_to_messages, "include_reasoning_content", False) is True

0 commit comments

Comments
 (0)