Skip to content

Commit b25c434

Browse files
committed
fix: working in feedback, making object typechecks less brittle
1 parent 9e20ebb commit b25c434

File tree

4 files changed

+58
-33
lines changed

4 files changed

+58
-33
lines changed

sentry_sdk/integrations/openai_agents/patches/tools.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
if TYPE_CHECKING:
1010
from typing import Any, Callable
1111

12+
import agents
13+
1214
try:
13-
import agents
15+
from agents import FunctionTool
1416
except ImportError:
15-
raise DidNotEnable("OpenAI Agents not installed")
17+
FunctionTool = None # type: ignore
1618

1719

1820
def _create_get_all_tools_wrapper(original_get_all_tools):
@@ -35,7 +37,7 @@ async def wrapped_get_all_tools(cls, agent, context_wrapper):
3537
wrapped_tools = []
3638
for tool in tools:
3739
# Wrap only the function tools (for now)
38-
if tool.__class__.__name__ != "FunctionTool":
40+
if not isinstance(tool, FunctionTool):
3941
wrapped_tools.append(tool)
4042
continue
4143

sentry_sdk/integrations/openai_agents/spans/execute_tool.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
import agents
1212
from typing import Any
1313

14+
try:
15+
from agents import FunctionTool
16+
except ImportError:
17+
FunctionTool = None # type: ignore
18+
1419

1520
def execute_tool_span(tool, *args, **kwargs):
1621
# type: (agents.Tool, *Any, **Any) -> sentry_sdk.tracing.Span
@@ -22,7 +27,7 @@ def execute_tool_span(tool, *args, **kwargs):
2227

2328
span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "execute_tool")
2429

25-
if tool.__class__.__name__ == "FunctionTool":
30+
if FunctionTool and isinstance(tool, FunctionTool):
2631
span.set_data(SPANDATA.GEN_AI_TOOL_TYPE, "function")
2732

2833
span.set_data(SPANDATA.GEN_AI_TOOL_NAME, tool.name)

sentry_sdk/integrations/openai_agents/utils.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
from typing import Any
1818
from agents import Usage
1919

20-
try:
21-
import agents
20+
import agents
2221

22+
try:
23+
from agents.items import McpCall
2324
except ImportError:
24-
raise DidNotEnable("OpenAI Agents not installed")
25+
McpCall = None # type: ignore
2526

2627

2728
def _capture_exception(exc):
@@ -178,7 +179,7 @@ def _set_output_data(span, result):
178179
def _create_mcp_execute_tool_spans(span, result):
179180
# type: (sentry_sdk.tracing.Span, agents.Result) -> None
180181
for output in result.output:
181-
if output.__class__.__name__ == "McpCall":
182+
if McpCall and isinstance(output, McpCall):
182183
with sentry_sdk.start_span(
183184
op=OP.GEN_AI_EXECUTE_TOOL,
184185
description=f"execute_tool {output.name}",

sentry_sdk/integrations/pydantic_ai/spans/ai_client.py

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,24 @@
1717
from typing import Any, List, Dict
1818
from pydantic_ai.usage import RequestUsage
1919

20+
try:
21+
from pydantic_ai.messages import (
22+
BaseToolCallPart,
23+
BaseToolReturnPart,
24+
SystemPromptPart,
25+
UserPromptPart,
26+
TextPart,
27+
ThinkingPart,
28+
)
29+
except ImportError:
30+
# Fallback if these classes are not available
31+
BaseToolCallPart = None # type: ignore
32+
BaseToolReturnPart = None # type: ignore
33+
SystemPromptPart = None # type: ignore
34+
UserPromptPart = None # type: ignore
35+
TextPart = None # type: ignore
36+
ThinkingPart = None # type: ignore
37+
2038

2139
def _set_usage_data(span, usage):
2240
# type: (sentry_sdk.tracing.Span, RequestUsage) -> None
@@ -63,24 +81,24 @@ def _set_input_messages(span, messages):
6381
if hasattr(msg, "parts"):
6482
for part in msg.parts:
6583
role = "user"
66-
if hasattr(part, "__class__"):
67-
if "System" in part.__class__.__name__:
68-
role = "system"
69-
elif (
70-
"Assistant" in part.__class__.__name__
71-
or "Text" in part.__class__.__name__
72-
or "ToolCall" in part.__class__.__name__
73-
):
74-
role = "assistant"
75-
elif "ToolReturn" in part.__class__.__name__:
76-
role = "tool"
84+
# Use isinstance checks with proper base classes
85+
if SystemPromptPart and isinstance(part, SystemPromptPart):
86+
role = "system"
87+
elif (
88+
(TextPart and isinstance(part, TextPart))
89+
or (ThinkingPart and isinstance(part, ThinkingPart))
90+
or (BaseToolCallPart and isinstance(part, BaseToolCallPart))
91+
):
92+
role = "assistant"
93+
elif BaseToolReturnPart and isinstance(part, BaseToolReturnPart):
94+
role = "tool"
7795

7896
content = [] # type: List[Dict[str, Any] | str]
7997
tool_calls = None
8098
tool_call_id = None
8199

82100
# Handle ToolCallPart (assistant requesting tool use)
83-
if "ToolCall" in part.__class__.__name__:
101+
if BaseToolCallPart and isinstance(part, BaseToolCallPart):
84102
tool_call_data = {}
85103
if hasattr(part, "tool_name"):
86104
tool_call_data["name"] = part.tool_name
@@ -89,7 +107,7 @@ def _set_input_messages(span, messages):
89107
if tool_call_data:
90108
tool_calls = [tool_call_data]
91109
# Handle ToolReturnPart (tool result)
92-
elif "ToolReturn" in part.__class__.__name__:
110+
elif BaseToolReturnPart and isinstance(part, BaseToolReturnPart):
93111
if hasattr(part, "tool_name"):
94112
tool_call_id = part.tool_name
95113
if hasattr(part, "content"):
@@ -144,18 +162,17 @@ def _set_output_data(span, response):
144162
tool_calls = []
145163

146164
for part in response.parts:
147-
if hasattr(part, "__class__"):
148-
if "Text" in part.__class__.__name__ and hasattr(part, "content"):
149-
texts.append(part.content)
150-
elif "ToolCall" in part.__class__.__name__:
151-
tool_call_data = {
152-
"type": "function",
153-
}
154-
if hasattr(part, "tool_name"):
155-
tool_call_data["name"] = part.tool_name
156-
if hasattr(part, "args"):
157-
tool_call_data["arguments"] = safe_serialize(part.args)
158-
tool_calls.append(tool_call_data)
165+
if TextPart and isinstance(part, TextPart) and hasattr(part, "content"):
166+
texts.append(part.content)
167+
elif BaseToolCallPart and isinstance(part, BaseToolCallPart):
168+
tool_call_data = {
169+
"type": "function",
170+
}
171+
if hasattr(part, "tool_name"):
172+
tool_call_data["name"] = part.tool_name
173+
if hasattr(part, "args"):
174+
tool_call_data["arguments"] = safe_serialize(part.args)
175+
tool_calls.append(tool_call_data)
159176

160177
if texts:
161178
set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, texts)

0 commit comments

Comments
 (0)