Skip to content

Fix LiteLLM thinking models with tool calling across providers #812

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,6 @@ cython_debug/
# PyPI configuration file
.pypirc
.aider*

# Claude Code settings
.claude/settings.local.json
46 changes: 46 additions & 0 deletions src/agents/extensions/models/litellm_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ async def _fetch_response(
stream: bool = False,
) -> litellm.types.utils.ModelResponse | tuple[Response, AsyncStream[ChatCompletionChunk]]:
converted_messages = Converter.items_to_messages(input)

# Fix for thinking models: Handle assistant messages with tool calls properly
if model_settings.reasoning:
converted_messages = self._fix_thinking_model_messages(converted_messages)

if system_instructions:
converted_messages.insert(
Expand Down Expand Up @@ -330,6 +334,48 @@ def _remove_not_given(self, value: Any) -> Any:
return None
return value

def _fix_thinking_model_messages(self, messages: list[dict]) -> list[dict]:
"""
Fix assistant messages for LiteLLM thinking models.

When reasoning is enabled, assistant messages with tool calls should not have
content - LiteLLM will handle the thinking blocks automatically for supported
thinking models that also support function calling.

Verified working with:
- Anthropic Claude Sonnet 4
- OpenAI o4-mini

Note: Some thinking models like OpenAI o1-mini/o1-preview don't support function calling yet.

This fixes issue #765: https://github.com/openai/openai-agents-python/issues/765
"""
logger.debug(f"Fixing messages for LiteLLM thinking model: {self.model}")
modified_messages = []

for i, message in enumerate(messages):
if (
message.get("role") == "assistant"
and message.get("tool_calls")
and len(message.get("tool_calls", [])) > 0
):
logger.debug(f"Message {i}: Removing content from assistant message with tool calls")
# This assistant message has tool calls, remove content for thinking models
modified_message = message.copy()

# Remove content entirely - let LiteLLM handle thinking blocks automatically
if "content" in modified_message:
del modified_message["content"]

logger.debug(f"Message {i}: Removed content, message now: {modified_message}")
modified_messages.append(modified_message)
else:
logger.debug(f"Message {i}: {message.get('role')} message, no modification needed")
modified_messages.append(message)

return modified_messages



class LitellmConverter:
@classmethod
Expand Down
Loading