Skip to content

Commit 1a1219d

Browse files
committed
wip
1 parent 1da5be6 commit 1a1219d

File tree

2 files changed

+588
-575
lines changed

2 files changed

+588
-575
lines changed

sentry_sdk/integrations/claude_agent_sdk.py

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@
1919
from claude_agent_sdk import (
2020
query as original_query,
2121
ClaudeSDKClient,
22-
AssistantMessage,
23-
ResultMessage,
24-
TextBlock,
25-
ToolUseBlock,
26-
ToolResultBlock,
2722
)
2823
except ImportError:
2924
raise DidNotEnable("claude-agent-sdk not installed")
@@ -36,6 +31,38 @@
3631
GEN_AI_SYSTEM = "claude-agent-sdk-python"
3732

3833

34+
def _is_assistant_message(message: "Any") -> bool:
35+
"""Check if message is an AssistantMessage using duck typing."""
36+
return hasattr(message, "content") and hasattr(message, "model")
37+
38+
39+
def _is_result_message(message: "Any") -> bool:
40+
"""Check if message is a ResultMessage using duck typing."""
41+
return hasattr(message, "usage") and hasattr(message, "total_cost_usd")
42+
43+
44+
def _is_text_block(block: "Any") -> bool:
45+
"""Check if block is a TextBlock using duck typing."""
46+
# TextBlock has 'text' but not 'tool_use_id' or 'name'
47+
return (
48+
hasattr(block, "text")
49+
and not hasattr(block, "tool_use_id")
50+
and not hasattr(block, "name")
51+
)
52+
53+
54+
def _is_tool_use_block(block: "Any") -> bool:
55+
"""Check if block is a ToolUseBlock using duck typing."""
56+
# ToolUseBlock has 'id', 'name', and 'input'
57+
return hasattr(block, "id") and hasattr(block, "name") and hasattr(block, "input")
58+
59+
60+
def _is_tool_result_block(block: "Any") -> bool:
61+
"""Check if block is a ToolResultBlock using duck typing."""
62+
# ToolResultBlock has 'tool_use_id'
63+
return hasattr(block, "tool_use_id")
64+
65+
3966
class ClaudeAgentSDKIntegration(Integration):
4067
identifier = "claude_agent_sdk"
4168
origin = f"auto.ai.{identifier}"
@@ -101,22 +128,20 @@ def _set_span_input_data(
101128

102129

103130
def _extract_text_from_message(message: "Any") -> "Optional[str]":
104-
if not isinstance(message, AssistantMessage):
131+
if not _is_assistant_message(message):
105132
return None
106133
text_parts = [
107-
block.text
108-
for block in getattr(message, "content", [])
109-
if isinstance(block, TextBlock) and hasattr(block, "text")
134+
block.text for block in getattr(message, "content", []) if _is_text_block(block)
110135
]
111136
return "".join(text_parts) if text_parts else None
112137

113138

114139
def _extract_tool_calls(message: "Any") -> "Optional[list]":
115-
if not isinstance(message, AssistantMessage):
140+
if not _is_assistant_message(message):
116141
return None
117142
tool_calls = []
118143
for block in getattr(message, "content", []):
119-
if isinstance(block, ToolUseBlock):
144+
if _is_tool_use_block(block):
120145
tool_call = {"name": getattr(block, "name", "unknown")}
121146
tool_input = getattr(block, "input", None)
122147
if tool_input is not None:
@@ -138,7 +163,7 @@ def _extract_message_data(messages: list) -> dict:
138163
}
139164

140165
for message in messages:
141-
if isinstance(message, AssistantMessage):
166+
if _is_assistant_message(message):
142167
text = _extract_text_from_message(message)
143168
if text:
144169
data["response_texts"].append(text)
@@ -150,7 +175,7 @@ def _extract_message_data(messages: list) -> dict:
150175
if not data["response_model"]:
151176
data["response_model"] = getattr(message, "model", None)
152177

153-
elif isinstance(message, ResultMessage):
178+
elif _is_result_message(message):
154179
data["total_cost"] = getattr(message, "total_cost_usd", None)
155180
usage = getattr(message, "usage", None)
156181
if isinstance(usage, dict):
@@ -264,8 +289,8 @@ def _end_invoke_agent_span(
264289

265290

266291
def _create_execute_tool_span(
267-
tool_use: "ToolUseBlock",
268-
tool_result: "Optional[ToolResultBlock]",
292+
tool_use: "Any",
293+
tool_result: "Optional[Any]",
269294
integration: "ClaudeAgentSDKIntegration",
270295
) -> "Span":
271296
tool_name = getattr(tool_use, "name", "unknown")
@@ -306,14 +331,14 @@ def _process_tool_executions(
306331
tool_results = {}
307332

308333
for message in messages:
309-
if not isinstance(message, AssistantMessage):
334+
if not _is_assistant_message(message):
310335
continue
311336
for block in getattr(message, "content", []):
312-
if isinstance(block, ToolUseBlock):
337+
if _is_tool_use_block(block):
313338
tool_id = getattr(block, "id", None)
314339
if tool_id:
315340
tool_uses[tool_id] = block
316-
elif isinstance(block, ToolResultBlock):
341+
elif _is_tool_result_block(block):
317342
tool_use_id = getattr(block, "tool_use_id", None)
318343
if tool_use_id:
319344
tool_results[tool_use_id] = block

0 commit comments

Comments
 (0)