fix: #2291 silence LiteLLM serializer warnings in streaming (opt-in) (#2295)

This commit is contained in:
Kazuhiro Sera
2026-01-12 10:26:12 +09:00
committed by GitHub
parent 87af6e3256
commit 9cc895818d
2 changed files with 90 additions and 0 deletions
@@ -1,6 +1,7 @@
from __future__ import annotations
import json
import os
import time
from collections.abc import AsyncIterator
from copy import copy
@@ -32,6 +33,7 @@ from openai.types.chat.chat_completion_message import (
)
from openai.types.chat.chat_completion_message_function_tool_call import Function
from openai.types.responses import Response
from pydantic import BaseModel
from ... import _debug
from ...agent_output import AgentOutputSchemaBase
@@ -53,6 +55,65 @@ from ...usage import Usage
from ...util._json import _to_dump_compatible
def _patch_litellm_serializer_warnings() -> None:
"""Ensure LiteLLM logging uses model_dump(warnings=False) when available."""
# Background: LiteLLM emits Pydantic serializer warnings for Message/Choices mismatches.
# See: https://github.com/BerriAI/litellm/issues/11759
# This patch relies on a private LiteLLM helper; if the name or signature changes,
# the wrapper should no-op or fall back to LiteLLM's default behavior. Revisit on upgrade.
# Remove this patch once the LiteLLM issue is resolved.
try:
from litellm.litellm_core_utils import litellm_logging as _litellm_logging
except Exception:
return
# Guard against double-patching if this module is imported multiple times.
if getattr(_litellm_logging, "_openai_agents_patched_serializer_warnings", False):
return
original = getattr(_litellm_logging, "_extract_response_obj_and_hidden_params", None)
if original is None:
return
def _wrapped_extract_response_obj_and_hidden_params(*args, **kwargs):
# init_response_obj is LiteLLM's raw response container (often a Pydantic BaseModel).
# Accept arbitrary args to stay compatible if LiteLLM changes the signature.
init_response_obj = args[0] if args else kwargs.get("init_response_obj")
if isinstance(init_response_obj, BaseModel):
hidden_params = getattr(init_response_obj, "_hidden_params", None)
try:
response_obj = init_response_obj.model_dump(warnings=False)
except TypeError:
response_obj = init_response_obj.model_dump()
if args:
response_obj_out, original_hidden = original(response_obj, *args[1:], **kwargs)
else:
updated_kwargs = dict(kwargs)
updated_kwargs["init_response_obj"] = response_obj
response_obj_out, original_hidden = original(**updated_kwargs)
return response_obj_out, hidden_params or original_hidden
return original(*args, **kwargs)
setattr( # noqa: B010
_litellm_logging,
"_extract_response_obj_and_hidden_params",
_wrapped_extract_response_obj_and_hidden_params,
)
setattr( # noqa: B010
_litellm_logging,
"_openai_agents_patched_serializer_warnings",
True,
)
# Set OPENAI_AGENTS_ENABLE_LITELLM_SERIALIZER_PATCH=true to opt in.
_enable_litellm_patch = os.getenv("OPENAI_AGENTS_ENABLE_LITELLM_SERIALIZER_PATCH", "")
if _enable_litellm_patch.lower() in ("1", "true"):
_patch_litellm_serializer_warnings()
class InternalChatCompletionMessage(ChatCompletionMessage):
"""
An internal subclass to carry reasoning_content and thinking_blocks without modifying the original model.
@@ -0,0 +1,29 @@
from __future__ import annotations
import importlib
import pytest
pytest.importorskip("litellm")
def test_litellm_logging_patch_env_var_controls_application(monkeypatch):
"""Assert the serializer patch only applies when the env var is enabled."""
litellm_logging = importlib.import_module("litellm.litellm_core_utils.litellm_logging")
litellm_model = importlib.import_module("agents.extensions.models.litellm_model")
monkeypatch.delenv("OPENAI_AGENTS_ENABLE_LITELLM_SERIALIZER_PATCH", raising=False)
litellm_logging = importlib.reload(litellm_logging)
importlib.reload(litellm_model)
assert hasattr(
litellm_logging,
"_extract_response_obj_and_hidden_params",
), "LiteLLM removed _extract_response_obj_and_hidden_params; revisit warning patch."
assert getattr(litellm_logging, "_openai_agents_patched_serializer_warnings", False) is False
monkeypatch.setenv("OPENAI_AGENTS_ENABLE_LITELLM_SERIALIZER_PATCH", "true")
litellm_logging = importlib.reload(litellm_logging)
importlib.reload(litellm_model)
assert getattr(litellm_logging, "_openai_agents_patched_serializer_warnings", False) is True