Skip to content
Merged
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
30 changes: 28 additions & 2 deletions sentry_sdk/integrations/pydantic_ai/spans/ai_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
_get_model_name,
_set_agent_data,
_set_available_tools,
_set_model_data,
)
from .utils import (
_serialize_binary_content_item,
Expand Down Expand Up @@ -306,7 +305,34 @@ def ai_client_context(
if model_name:
context.span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model_name)

_set_model_data(context.span, agent, model_settings)
# Extract model settings
settings = model_settings
if not settings and agent and hasattr(agent, "model_settings"):
settings = agent.model_settings

if settings:
settings_map = {
"max_tokens": SPANDATA.GEN_AI_REQUEST_MAX_TOKENS,
"temperature": SPANDATA.GEN_AI_REQUEST_TEMPERATURE,
"top_p": SPANDATA.GEN_AI_REQUEST_TOP_P,
"frequency_penalty": SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY,
"presence_penalty": SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY,
}

# ModelSettings is a TypedDict (dict at runtime), so use dict access
if isinstance(settings, dict):
for setting_name, spandata_key in settings_map.items():
value = settings.get(setting_name)
if value is not None:
context.span.set_attribute(spandata_key, value) # type: ignore[arg-type]
else:
# Fallback for object-style settings
for setting_name, spandata_key in settings_map.items():
if hasattr(settings, setting_name):
value = getattr(settings, setting_name)
if value is not None:
context.span.set_attribute(spandata_key, value)

_set_available_tools(context.span, agent)

# Set input messages (full conversation history)
Expand Down
2 changes: 0 additions & 2 deletions sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from ..consts import SPAN_ORIGIN
from ..utils import (
_set_agent_data,
_set_model_data,
)
from .utils import (
_serialize_binary_content_item,
Expand Down Expand Up @@ -53,7 +52,6 @@ def invoke_agent_span(
)

_set_agent_data(span, agent)
_set_model_data(span, agent, model_settings)

# Add user prompt and system prompts if available and prompts are enabled
if not sentry_sdk.get_client().options["data_collection"]["gen_ai"]["inputs"]:
Expand Down
43 changes: 0 additions & 43 deletions sentry_sdk/integrations/pydantic_ai/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

from pydantic_ai import Agent
from pydantic_ai.models import AbstractModel, Model
from pydantic_ai.realtime.settings import RealtimeModelSettings
from pydantic_ai.settings import ModelSettings


def _set_agent_data(span: "Span", agent: "Optional[Agent]") -> None:
Expand Down Expand Up @@ -55,47 +53,6 @@ def _get_model_name(
return str(model_obj)


def _set_model_data(
span: "Span",
agent: "Optional[Agent]",
model_settings: "Optional[Union[ModelSettings, RealtimeModelSettings]]",
) -> None:
"""Set model-related data on a span.

Args:
span: The span to set data on
model: Model object (can be None, will try to get from agent if not provided)
model_settings: Model settings (can be None, will try to get from agent if not provided)
"""
# Extract model settings
settings = model_settings
if not settings and agent and hasattr(agent, "model_settings"):
settings = agent.model_settings

if settings:
settings_map = {
"max_tokens": SPANDATA.GEN_AI_REQUEST_MAX_TOKENS,
"temperature": SPANDATA.GEN_AI_REQUEST_TEMPERATURE,
"top_p": SPANDATA.GEN_AI_REQUEST_TOP_P,
"frequency_penalty": SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY,
"presence_penalty": SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY,
}

# ModelSettings is a TypedDict (dict at runtime), so use dict access
if isinstance(settings, dict):
for setting_name, spandata_key in settings_map.items():
value = settings.get(setting_name)
if value is not None:
span.set_attribute(spandata_key, value) # type: ignore[arg-type]
else:
# Fallback for object-style settings
for setting_name, spandata_key in settings_map.items():
if hasattr(settings, setting_name):
value = getattr(settings, setting_name)
if value is not None:
span.set_attribute(spandata_key, value)


def _set_available_tools(span: "Span", agent: "Optional[Agent[Any, Any]]") -> None:
"""Set available tools data on a span from an agent's function toolset.

Expand Down
Loading