Skip to content

Commit 7fa0b37

Browse files
committed
fix(integrations): pydantic-ai: properly format binary input message parts to be conformant with the gen_ai.request.messages structure
1 parent 3d3ce5b commit 7fa0b37

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

sentry_sdk/integrations/pydantic_ai/spans/ai_client.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
import base64
12
import sentry_sdk
2-
from sentry_sdk.ai.utils import set_data_normalized
3+
from sentry_sdk.ai.utils import (
4+
normalize_message_roles,
5+
set_data_normalized,
6+
truncate_and_annotate_messages,
7+
)
38
from sentry_sdk.consts import OP, SPANDATA
49
from sentry_sdk.utils import safe_serialize
510

@@ -29,6 +34,7 @@
2934
UserPromptPart,
3035
TextPart,
3136
ThinkingPart,
37+
BinaryContent,
3238
)
3339
except ImportError:
3440
# Fallback if these classes are not available
@@ -38,6 +44,7 @@
3844
UserPromptPart = None
3945
TextPart = None
4046
ThinkingPart = None
47+
BinaryContent = None
4148

4249

4350
def _set_input_messages(span: "sentry_sdk.tracing.Span", messages: "Any") -> None:
@@ -107,6 +114,16 @@ def _set_input_messages(span: "sentry_sdk.tracing.Span", messages: "Any") -> Non
107114
for item in part.content:
108115
if isinstance(item, str):
109116
content.append({"type": "text", "text": item})
117+
elif BinaryContent and isinstance(item, BinaryContent):
118+
breakpoint()
119+
content.append(
120+
{
121+
"type": "blob",
122+
"modality": item.media_type.split("/")[0],
123+
"mime_type": item.media_type,
124+
"content": f"data:{item.media_type};base64,{base64.b64encode(item.data).decode('utf-8')}",
125+
}
126+
)
110127
else:
111128
content.append(safe_serialize(item))
112129
else:
@@ -124,8 +141,13 @@ def _set_input_messages(span: "sentry_sdk.tracing.Span", messages: "Any") -> Non
124141
formatted_messages.append(message)
125142

126143
if formatted_messages:
144+
normalized_messages = normalize_message_roles(formatted_messages)
145+
scope = sentry_sdk.get_current_scope()
146+
messages_data = truncate_and_annotate_messages(
147+
normalized_messages, span, scope
148+
)
127149
set_data_normalized(
128-
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, formatted_messages, unpack=False
150+
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False
129151
)
130152
except Exception:
131153
# If we fail to format messages, just skip it

sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import sentry_sdk
2-
from sentry_sdk.ai.utils import get_start_span_function, set_data_normalized
2+
from sentry_sdk.ai.utils import (
3+
get_start_span_function,
4+
normalize_message_roles,
5+
set_data_normalized,
6+
truncate_and_annotate_messages,
7+
)
38
from sentry_sdk.consts import OP, SPANDATA
49

510
from ..consts import SPAN_ORIGIN
@@ -102,8 +107,13 @@ def invoke_agent_span(
102107
)
103108

104109
if messages:
110+
normalized_messages = normalize_message_roles(messages)
111+
scope = sentry_sdk.get_current_scope()
112+
messages_data = truncate_and_annotate_messages(
113+
normalized_messages, span, scope
114+
)
105115
set_data_normalized(
106-
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages, unpack=False
116+
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False
107117
)
108118

109119
return span

sentry_sdk/integrations/pydantic_ai/spans/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from typing import TYPE_CHECKING
77

88
if TYPE_CHECKING:
9-
from typing import Union
9+
from typing import Union, Dict, Any, List
1010
from pydantic_ai.usage import RequestUsage, RunUsage # type: ignore
1111

1212

0 commit comments

Comments
 (0)