Skip to content
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
10 changes: 6 additions & 4 deletions sentry_sdk/integrations/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,15 +730,15 @@ 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:
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_message.model_dump()
)

if len(output_messages["tool"]) > 0:
Expand All @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/openai_agents/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
51 changes: 50 additions & 1 deletion tests/integrations/openai_agents/test_openai_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -20,6 +22,7 @@
from agents.items import (
ResponseFunctionToolCall,
ResponseOutputMessage,
ResponseOutputRefusal,
ResponseOutputText,
)
from agents.models.openai_responses import OpenAIResponsesModel
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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]