Skip to content
Draft
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
17 changes: 1 addition & 16 deletions sentry_sdk/integrations/pydantic_ai/spans/ai_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import sentry_sdk
from sentry_sdk.ai.utils import (
normalize_message_roles,
set_data_normalized,
truncate_and_annotate_messages,
)
from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.utils import safe_serialize
Expand All @@ -20,8 +18,6 @@
get_is_streaming,
)
from .utils import (
_serialize_binary_content_item,
_serialize_image_url_item,
_set_usage_data,
)

Expand All @@ -40,7 +36,6 @@
UserPromptPart,
TextPart,
ThinkingPart,
BinaryContent,
ImageUrl,
)
except ImportError:
Expand All @@ -51,7 +46,6 @@
UserPromptPart = None
TextPart = None
ThinkingPart = None
BinaryContent = None
ImageUrl = None


Expand Down Expand Up @@ -161,10 +155,6 @@ def _set_input_messages(span: "sentry_sdk.tracing.Span", messages: "Any") -> Non
for item in part.content:
if isinstance(item, str):
content.append({"type": "text", "text": item})
elif ImageUrl and isinstance(item, ImageUrl):
content.append(_serialize_image_url_item(item))
elif BinaryContent and isinstance(item, BinaryContent):
content.append(_serialize_binary_content_item(item))
else:
content.append(safe_serialize(item))
else:
Expand All @@ -181,13 +171,8 @@ def _set_input_messages(span: "sentry_sdk.tracing.Span", messages: "Any") -> Non
formatted_messages.append(message)

if formatted_messages:
normalized_messages = normalize_message_roles(formatted_messages)
scope = sentry_sdk.get_current_scope()
messages_data = truncate_and_annotate_messages(
normalized_messages, span, scope
)
set_data_normalized(
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, formatted_messages, unpack=False
)
except Exception:
# If we fail to format messages, just skip it
Expand Down
21 changes: 1 addition & 20 deletions sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import sentry_sdk
from sentry_sdk.ai.utils import (
get_start_span_function,
normalize_message_roles,
set_data_normalized,
truncate_and_annotate_messages,
)
from sentry_sdk.consts import OP, SPANDATA

Expand All @@ -15,8 +13,6 @@
_should_send_prompts,
)
from .utils import (
_serialize_binary_content_item,
_serialize_image_url_item,
_set_usage_data,
)

Expand All @@ -25,12 +21,6 @@
if TYPE_CHECKING:
from typing import Any

try:
from pydantic_ai.messages import BinaryContent, ImageUrl # type: ignore
except ImportError:
BinaryContent = None
ImageUrl = None


def invoke_agent_span(
user_prompt: "Any",
Expand Down Expand Up @@ -108,10 +98,6 @@ def invoke_agent_span(
for item in user_prompt:
if isinstance(item, str):
content.append({"text": item, "type": "text"})
elif ImageUrl and isinstance(item, ImageUrl):
content.append(_serialize_image_url_item(item))
elif BinaryContent and isinstance(item, BinaryContent):
content.append(_serialize_binary_content_item(item))
if content:
messages.append(
{
Expand All @@ -121,13 +107,8 @@ def invoke_agent_span(
)

if messages:
normalized_messages = normalize_message_roles(messages)
scope = sentry_sdk.get_current_scope()
messages_data = truncate_and_annotate_messages(
normalized_messages, span, scope
)
set_data_normalized(
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages, unpack=False
)

return span
Expand Down
36 changes: 1 addition & 35 deletions sentry_sdk/integrations/pydantic_ai/spans/utils.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,16 @@
"""Utility functions for PydanticAI span instrumentation."""

import sentry_sdk
from sentry_sdk._types import BLOB_DATA_SUBSTITUTE
from sentry_sdk.ai.utils import get_modality_from_mime_type
from sentry_sdk.consts import SPANDATA

from sentry_sdk.ai.consts import DATA_URL_BASE64_REGEX

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Union, Dict, Any
from typing import Union
from pydantic_ai.usage import RequestUsage, RunUsage # type: ignore


def _serialize_image_url_item(item: "Any") -> "Dict[str, Any]":
"""Serialize an ImageUrl content item for span data.

For data URLs containing base64-encoded images, the content is redacted.
For regular HTTP URLs, the URL string is preserved.
"""
url = str(item.url)
data_url_match = DATA_URL_BASE64_REGEX.match(url)

if data_url_match:
return {
"type": "image",
"content": BLOB_DATA_SUBSTITUTE,
}

return {
"type": "image",
"content": url,
}


def _serialize_binary_content_item(item: "Any") -> "Dict[str, Any]":
"""Serialize a BinaryContent item for span data, redacting the blob data."""
return {
"type": "blob",
"modality": get_modality_from_mime_type(item.media_type),
"mime_type": item.media_type,
"content": BLOB_DATA_SUBSTITUTE,
}


def _set_usage_data(
span: "sentry_sdk.tracing.Span", usage: "Union[RequestUsage, RunUsage]"
) -> None:
Expand Down
Loading
Loading