diff --git a/sentry_sdk/integrations/openai_agents/spans/ai_client.py b/sentry_sdk/integrations/openai_agents/spans/ai_client.py index d075d3c9a8..c3470c8f60 100644 --- a/sentry_sdk/integrations/openai_agents/spans/ai_client.py +++ b/sentry_sdk/integrations/openai_agents/spans/ai_client.py @@ -5,7 +5,6 @@ from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import has_data_collection_enabled try: @@ -210,41 +209,27 @@ def ai_client_span( client_options = sentry_sdk.get_client().options - span_streaming = has_span_streaming_enabled(client_options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"chat {model_name}", - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - }, - ) - - set_on_span = span.set_attribute - else: - span = sentry_sdk.start_span( - op=OP.GEN_AI_CHAT, - name=f"chat {model_name}", - origin=SPAN_ORIGIN, - ) - # TODO-anton: remove hardcoded stuff and replace something that also works for embedding and so on - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat") - - set_on_span = span.set_data + span = sentry_sdk.traces.start_span( + name=f"chat {model_name}", + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "chat", + }, + ) _set_agent_data(span, agent) if has_data_collection_enabled(client_options): if client_options["data_collection"]["gen_ai"]["inputs"]: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_TOOL_DEFINITIONS, json.dumps(_transform_tool_definitions(agent.tools)), ) else: # This is set unconditionally prior to data collection being introduced. # Remove this block once data collection is fully rolled out - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_TOOL_DEFINITIONS, json.dumps(_transform_tool_definitions(agent.tools)), ) @@ -255,7 +240,7 @@ def ai_client_span( def update_ai_client_span( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "StreamedSpan", response: "Any", response_model: "Optional[str]" = None, agent: "Optional[Agent]" = None, @@ -267,17 +252,13 @@ def update_ai_client_span( if hasattr(response, "output") and response.output: _set_output_data(span, response) - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - if response_model is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model) elif hasattr(response, "model") and response.model: - set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, str(response.model)) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, str(response.model)) # Set conversation ID from agent if available if agent: conv_id = getattr(agent, "_sentry_conversation_id", None) if conv_id: - set_on_span(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) + span.set_attribute(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) diff --git a/sentry_sdk/integrations/openai_agents/spans/execute_tool.py b/sentry_sdk/integrations/openai_agents/spans/execute_tool.py index 734789b030..f8005113e7 100644 --- a/sentry_sdk/integrations/openai_agents/spans/execute_tool.py +++ b/sentry_sdk/integrations/openai_agents/spans/execute_tool.py @@ -4,7 +4,6 @@ from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS from sentry_sdk.scope import should_send_default_pii from sentry_sdk.traces import SpanStatus, StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import has_data_collection_enabled from ..consts import SPAN_ORIGIN @@ -19,30 +18,16 @@ def execute_tool_span( tool: "agents.Tool", *args: "Any", **kwargs: "Any" ) -> "Union[sentry_sdk.tracing.Span, StreamedSpan]": - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"execute_tool {tool.name}", - attributes={ - "sentry.op": OP.GEN_AI_EXECUTE_TOOL, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "execute_tool", - SPANDATA.GEN_AI_TOOL_NAME: tool.name, - SPANDATA.GEN_AI_TOOL_DESCRIPTION: tool.description, - }, - ) - else: - span = sentry_sdk.start_span( - op=OP.GEN_AI_EXECUTE_TOOL, - name=f"execute_tool {tool.name}", - origin=SPAN_ORIGIN, - ) - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "execute_tool") - - span.set_data(SPANDATA.GEN_AI_TOOL_NAME, tool.name) - span.set_data(SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool.description) + span = sentry_sdk.traces.start_span( + name=f"execute_tool {tool.name}", + attributes={ + "sentry.op": OP.GEN_AI_EXECUTE_TOOL, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "execute_tool", + SPANDATA.GEN_AI_TOOL_NAME: tool.name, + SPANDATA.GEN_AI_TOOL_DESCRIPTION: tool.description, + }, + ) return span diff --git a/sentry_sdk/integrations/openai_agents/spans/handoff.py b/sentry_sdk/integrations/openai_agents/spans/handoff.py index ea91464afb..9fa48b431d 100644 --- a/sentry_sdk/integrations/openai_agents/spans/handoff.py +++ b/sentry_sdk/integrations/openai_agents/spans/handoff.py @@ -2,7 +2,6 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.tracing_utils import has_span_streaming_enabled from ..consts import SPAN_ORIGIN @@ -13,29 +12,15 @@ def handoff_span( context: "agents.RunContextWrapper", from_agent: "agents.Agent", to_agent_name: str ) -> None: - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - with sentry_sdk.traces.start_span( - name=f"handoff from {from_agent.name} to {to_agent_name}", - attributes={ - "sentry.op": OP.GEN_AI_HANDOFF, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "handoff", - }, - ) as span: - # Add conversation ID from agent - conv_id = getattr(from_agent, "_sentry_conversation_id", None) - if conv_id: - span.set_attribute(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) - else: - with sentry_sdk.start_span( - op=OP.GEN_AI_HANDOFF, - name=f"handoff from {from_agent.name} to {to_agent_name}", - origin=SPAN_ORIGIN, - ) as span: - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "handoff") - - # Add conversation ID from agent - conv_id = getattr(from_agent, "_sentry_conversation_id", None) - if conv_id: - span.set_data(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) + with sentry_sdk.traces.start_span( + name=f"handoff from {from_agent.name} to {to_agent_name}", + attributes={ + "sentry.op": OP.GEN_AI_HANDOFF, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "handoff", + }, + ) as span: + # Add conversation ID from agent + conv_id = getattr(from_agent, "_sentry_conversation_id", None) + if conv_id: + span.set_attribute(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) diff --git a/sentry_sdk/integrations/openai_agents/spans/invoke_agent.py b/sentry_sdk/integrations/openai_agents/spans/invoke_agent.py index d8cc0c14a8..68483b0ef1 100644 --- a/sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +++ b/sentry_sdk/integrations/openai_agents/spans/invoke_agent.py @@ -2,7 +2,6 @@ import sentry_sdk from sentry_sdk.ai.utils import ( - get_start_span_function, normalize_message_roles, set_data_normalized, truncate_and_annotate_messages, @@ -28,26 +27,14 @@ def invoke_agent_span( context: "agents.RunContextWrapper", agent: "agents.Agent", kwargs: "dict[str, Any]" ) -> "Union[sentry_sdk.tracing.Span, StreamedSpan]": client_options = sentry_sdk.get_client().options - span_streaming = has_span_streaming_enabled(client_options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"invoke_agent {agent.name}", - attributes={ - "sentry.op": OP.GEN_AI_INVOKE_AGENT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", - }, - ) - else: - start_span_function = get_start_span_function() - span = start_span_function( - op=OP.GEN_AI_INVOKE_AGENT, - name=f"invoke_agent {agent.name}", - origin=SPAN_ORIGIN, - ) - span.__enter__() - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent") + span = sentry_sdk.traces.start_span( + name=f"invoke_agent {agent.name}", + attributes={ + "sentry.op": OP.GEN_AI_INVOKE_AGENT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", + }, + ) record_inputs = False if has_data_collection_enabled(client_options): diff --git a/sentry_sdk/integrations/openai_agents/utils.py b/sentry_sdk/integrations/openai_agents/utils.py index e819b5e555..6a45777d0c 100644 --- a/sentry_sdk/integrations/openai_agents/utils.py +++ b/sentry_sdk/integrations/openai_agents/utils.py @@ -26,7 +26,7 @@ ) if TYPE_CHECKING: - from typing import Any, Union + from typing import Any from agents import TResponseInputItem, Usage @@ -48,21 +48,17 @@ def _capture_exception(exc: "Any") -> None: sentry_sdk.capture_event(event, hint=hint) -def _set_agent_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", agent: "agents.Agent" -) -> None: - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - - set_on_span( +def _set_agent_data(span: "StreamedSpan", agent: "agents.Agent") -> None: + span.set_attribute( SPANDATA.GEN_AI_SYSTEM, "openai" ) # See footnote for https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-system for explanation why. - set_on_span(SPANDATA.GEN_AI_AGENT_NAME, agent.name) + span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, agent.name) if agent.model_settings.max_tokens: - set_on_span(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, agent.model_settings.max_tokens) + span.set_attribute( + SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, agent.model_settings.max_tokens + ) # Get model name from agent.model or fall back to request model (for when agent.model is None/default) model_name = None @@ -72,50 +68,45 @@ def _set_agent_data( model_name = agent._sentry_request_model if model_name: - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) if agent.model_settings.presence_penalty: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, agent.model_settings.presence_penalty, ) if agent.model_settings.temperature: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_TEMPERATURE, agent.model_settings.temperature ) if agent.model_settings.top_p: - set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_P, agent.model_settings.top_p) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_P, agent.model_settings.top_p) if agent.model_settings.frequency_penalty: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, agent.model_settings.frequency_penalty, ) -def _set_usage_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", usage: "Usage" -) -> None: - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - set_on_span(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage.input_tokens) - set_on_span( +def _set_usage_data(span: "StreamedSpan", usage: "Usage") -> None: + span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage.input_tokens) + span.set_attribute( SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, usage.input_tokens_details.cached_tokens, ) - set_on_span(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens) - set_on_span( + span.set_attribute(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens) + span.set_attribute( SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, usage.output_tokens_details.reasoning_tokens, ) - set_on_span(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage.total_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage.total_tokens) def _set_input_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "StreamedSpan", get_response_kwargs: "dict[str, Any]", ) -> None: client = sentry_sdk.get_client() @@ -205,9 +196,7 @@ def _set_input_data( ) -def _set_output_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", result: "Any" -) -> None: +def _set_output_data(span: "StreamedSpan", result: "Any") -> None: client = sentry_sdk.get_client() record_outputs = False if has_data_collection_enabled(client.options):