From 8012ab8bbcdcf11bd1df125da2298f765631a555 Mon Sep 17 00:00:00 2001 From: AP Date: Mon, 5 Oct 2026 11:09:58 +0530 Subject: [PATCH 1/4] fix: use model_dump() instead of deprecated dict() in OpenAI output paths The pydantic v1 .dict() API emits PydanticDeprecatedSince20 on pydantic v2, which breaks anyone running with DeprecationWarnings as errors. Every supported openai/openai-agents version requires pydantic v2, so model_dump() is a drop-in replacement here. Fixes #7827. --- sentry_sdk/integrations/openai.py | 10 ++-- .../integrations/openai_agents/utils.py | 4 +- .../openai_agents/test_openai_agents.py | 51 ++++++++++++++++++- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 742b693245..42ecb0ec5e 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -730,7 +730,7 @@ def _set_common_output_data( if record_outputs: for output in response.output: if output.type == "function_call": - output_messages["tool"].append(output.dict()) + output_messages["tool"].append(output.model_dump()) elif output.type == "message": for output_message in output.content: try: @@ -738,7 +738,7 @@ def _set_common_output_data( except AttributeError: # Unknown output message type, just return the json output_messages["response"].append( - output_message.dict() + output_message.model_dump() ) if len(output_messages["tool"]) > 0: @@ -761,14 +761,16 @@ def _set_common_output_data( ): for output in response.output: if output.type == "function_call": - output_messages["tool"].append(output.dict()) + output_messages["tool"].append(output.model_dump()) elif output.type == "message": for output_message in output.content: try: output_messages["response"].append(output_message.text) # type: ignore[union-attr] except AttributeError: # Unknown output message type, just return the json - output_messages["response"].append(output_message.dict()) + output_messages["response"].append( + output_message.model_dump() + ) if len(output_messages["tool"]) > 0: set_data_normalized( diff --git a/sentry_sdk/integrations/openai_agents/utils.py b/sentry_sdk/integrations/openai_agents/utils.py index 01303e0e58..0e160193ed 100644 --- a/sentry_sdk/integrations/openai_agents/utils.py +++ b/sentry_sdk/integrations/openai_agents/utils.py @@ -226,14 +226,14 @@ def _set_output_data( for output in result.output: if output.type == "function_call": - output_messages["tool"].append(output.dict()) + output_messages["tool"].append(output.model_dump()) elif output.type == "message": for output_message in output.content: try: output_messages["response"].append(output_message.text) except AttributeError: # Unknown output message type, just return the json - output_messages["response"].append(output_message.dict()) + output_messages["response"].append(output_message.model_dump()) if record_outputs and len(output_messages["tool"]) > 0: if isinstance(span, StreamedSpan): diff --git a/tests/integrations/openai_agents/test_openai_agents.py b/tests/integrations/openai_agents/test_openai_agents.py index 8bc49a2c9f..13a336441d 100644 --- a/tests/integrations/openai_agents/test_openai_agents.py +++ b/tests/integrations/openai_agents/test_openai_agents.py @@ -2,6 +2,8 @@ import json import logging import os +import warnings +from types import SimpleNamespace from unittest import mock from unittest.mock import MagicMock, patch @@ -20,6 +22,7 @@ from agents.items import ( ResponseFunctionToolCall, ResponseOutputMessage, + ResponseOutputRefusal, ResponseOutputText, ) from agents.models.openai_responses import OpenAIResponsesModel @@ -72,7 +75,11 @@ from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.openai_agents import OpenAIAgentsIntegration -from sentry_sdk.integrations.openai_agents.utils import _set_input_data, safe_serialize +from sentry_sdk.integrations.openai_agents.utils import ( + _set_input_data, + _set_output_data, + safe_serialize, +) from sentry_sdk.integrations.stdlib import StdlibIntegration from sentry_sdk.utils import package_version, parse_version @@ -7483,3 +7490,45 @@ async def test_runner_run_streamed_with_starting_agent_kwarg( (transaction,) = events assert transaction["transaction"] == "test_agent workflow" + + +def test_set_output_data_tool_calls_no_pydantic_deprecation(sentry_init): + """Serializing tool-call output must not use the deprecated pydantic v1 API. + + Regression test for GH-7827: _set_output_data called BaseModel.dict(), + which raises PydanticDeprecatedSince20 when DeprecationWarnings are errors. + """ + sentry_init( + integrations=[OpenAIAgentsIntegration()], + send_default_pii=True, + traces_sample_rate=1.0, + ) + + tool_call = ResponseFunctionToolCall( + type="function_call", + id="call_1", + call_id="call_1", + name="get_weather", + arguments='{"city": "Berlin"}', + status="completed", + ) + refusal = ResponseOutputRefusal(type="refusal", refusal="I cannot help.") + message = ResponseOutputMessage( + type="message", + id="msg_1", + role="assistant", + content=[refusal], + status="completed", + ) + result = SimpleNamespace(output=[tool_call, message]) + + with start_span(op="test") as span: + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + _set_output_data(span, result) + + tool_calls = json.loads(span._data[SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS]) + assert tool_calls[0]["name"] == "get_weather" + assert tool_calls[0]["arguments"] == '{"city": "Berlin"}' + + assert "I cannot help." in span._data[SPANDATA.GEN_AI_RESPONSE_TEXT] From 90324f1b021016410bf7580e513b9f6446bc62c0 Mon Sep 17 00:00:00 2001 From: AP Date: Mon, 5 Oct 2026 14:54:34 +0530 Subject: [PATCH 2/4] test: drop redundant pydantic deprecation regression test Maintainer feedback: the new test duplicates coverage already provided by the existing suite, so it is not needed. The fix itself (model_dump() instead of dict()) is unchanged. --- .../openai_agents/test_openai_agents.py | 46 ------------------- 1 file changed, 46 deletions(-) diff --git a/tests/integrations/openai_agents/test_openai_agents.py b/tests/integrations/openai_agents/test_openai_agents.py index 13a336441d..a98d2fff30 100644 --- a/tests/integrations/openai_agents/test_openai_agents.py +++ b/tests/integrations/openai_agents/test_openai_agents.py @@ -2,8 +2,6 @@ import json import logging import os -import warnings -from types import SimpleNamespace from unittest import mock from unittest.mock import MagicMock, patch @@ -22,7 +20,6 @@ from agents.items import ( ResponseFunctionToolCall, ResponseOutputMessage, - ResponseOutputRefusal, ResponseOutputText, ) from agents.models.openai_responses import OpenAIResponsesModel @@ -77,7 +74,6 @@ from sentry_sdk.integrations.openai_agents import OpenAIAgentsIntegration from sentry_sdk.integrations.openai_agents.utils import ( _set_input_data, - _set_output_data, safe_serialize, ) from sentry_sdk.integrations.stdlib import StdlibIntegration @@ -7490,45 +7486,3 @@ async def test_runner_run_streamed_with_starting_agent_kwarg( (transaction,) = events assert transaction["transaction"] == "test_agent workflow" - - -def test_set_output_data_tool_calls_no_pydantic_deprecation(sentry_init): - """Serializing tool-call output must not use the deprecated pydantic v1 API. - - Regression test for GH-7827: _set_output_data called BaseModel.dict(), - which raises PydanticDeprecatedSince20 when DeprecationWarnings are errors. - """ - sentry_init( - integrations=[OpenAIAgentsIntegration()], - send_default_pii=True, - traces_sample_rate=1.0, - ) - - tool_call = ResponseFunctionToolCall( - type="function_call", - id="call_1", - call_id="call_1", - name="get_weather", - arguments='{"city": "Berlin"}', - status="completed", - ) - refusal = ResponseOutputRefusal(type="refusal", refusal="I cannot help.") - message = ResponseOutputMessage( - type="message", - id="msg_1", - role="assistant", - content=[refusal], - status="completed", - ) - result = SimpleNamespace(output=[tool_call, message]) - - with start_span(op="test") as span: - with warnings.catch_warnings(): - warnings.simplefilter("error", DeprecationWarning) - _set_output_data(span, result) - - tool_calls = json.loads(span._data[SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS]) - assert tool_calls[0]["name"] == "get_weather" - assert tool_calls[0]["arguments"] == '{"city": "Berlin"}' - - assert "I cannot help." in span._data[SPANDATA.GEN_AI_RESPONSE_TEXT] From 4496cf4143b2d7333722b205d3498b173427f1ec Mon Sep 17 00:00:00 2001 From: AP Date: Mon, 5 Oct 2026 16:29:17 +0530 Subject: [PATCH 3/4] fix: scope model_dump() migration to the openai-agents integration openai-python supports Pydantic v1 (where model_dump() doesn't exist), so revert the .dict() -> model_dump() change in the openai-python integration and keep it only in sentry_sdk/integrations/openai_agents/utils.py, where the openai-agents SDK guarantees Pydantic v2. Also fold the test import back to a single line; the multi-line form was only needed for the removed regression test's extra import. --- sentry_sdk/integrations/openai.py | 12 ++++-------- .../integrations/openai_agents/test_openai_agents.py | 5 +---- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 42ecb0ec5e..c0fd4c4740 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -730,16 +730,14 @@ def _set_common_output_data( if record_outputs: for output in response.output: if output.type == "function_call": - output_messages["tool"].append(output.model_dump()) + output_messages["tool"].append(output.dict()) elif output.type == "message": for output_message in output.content: try: output_messages["response"].append(output_message.text) # type: ignore[union-attr] except AttributeError: # Unknown output message type, just return the json - output_messages["response"].append( - output_message.model_dump() - ) + output_messages["response"].append(output_message.dict()) if len(output_messages["tool"]) > 0: set_data_normalized( @@ -761,16 +759,14 @@ def _set_common_output_data( ): for output in response.output: if output.type == "function_call": - output_messages["tool"].append(output.model_dump()) + output_messages["tool"].append(output.dict()) elif output.type == "message": for output_message in output.content: try: output_messages["response"].append(output_message.text) # type: ignore[union-attr] except AttributeError: # Unknown output message type, just return the json - output_messages["response"].append( - output_message.model_dump() - ) + output_messages["response"].append(output_message.dict()) if len(output_messages["tool"]) > 0: set_data_normalized( diff --git a/tests/integrations/openai_agents/test_openai_agents.py b/tests/integrations/openai_agents/test_openai_agents.py index a98d2fff30..8bc49a2c9f 100644 --- a/tests/integrations/openai_agents/test_openai_agents.py +++ b/tests/integrations/openai_agents/test_openai_agents.py @@ -72,10 +72,7 @@ from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.openai_agents import OpenAIAgentsIntegration -from sentry_sdk.integrations.openai_agents.utils import ( - _set_input_data, - safe_serialize, -) +from sentry_sdk.integrations.openai_agents.utils import _set_input_data, safe_serialize from sentry_sdk.integrations.stdlib import StdlibIntegration from sentry_sdk.utils import package_version, parse_version From 74505352f77ad2989e4cd5cc59533ee7a354cd93 Mon Sep 17 00:00:00 2001 From: AP Date: Mon, 5 Oct 2026 19:00:26 +0530 Subject: [PATCH 4/4] fix(openai): revert incidental formatting-only change Restores the original multi-line form around output_message.dict(); no behavioral change. The model_dump() migration now applies only to the openai-agents integration, per review. --- sentry_sdk/integrations/openai.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index c0fd4c4740..742b693245 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -737,7 +737,9 @@ def _set_common_output_data( output_messages["response"].append(output_message.text) # type: ignore[union-attr] except AttributeError: # Unknown output message type, just return the json - output_messages["response"].append(output_message.dict()) + output_messages["response"].append( + output_message.dict() + ) if len(output_messages["tool"]) > 0: set_data_normalized(