-
Notifications
You must be signed in to change notification settings - Fork 647
ref(openai-agents): Use first class agent hooks when available #7029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3cef85d
eb9bd68
f60881e
0e7155a
b273a1d
b5ae6b3
9c8074d
573480b
9210726
d555e9c
517d837
002ec0a
9fe9910
01fd3b1
0759b8b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| if TYPE_CHECKING: | ||
| from typing import Any, Awaitable, Callable, Optional, Union | ||
|
|
||
| from agents import TResponseInputItem | ||
| from agents.run_internal.run_steps import SingleStepResult | ||
|
|
||
| from sentry_sdk.tracing import Span | ||
|
|
@@ -49,7 +50,7 @@ | |
| context_wrapper: "agents.RunContextWrapper", | ||
| agent: "agents.Agent", | ||
| should_run_agent_start_hooks: bool, | ||
| span_kwargs: "dict[str, Any]", | ||
| turn_input: "Optional[list[TResponseInputItem]]", | ||
| is_streaming: bool = False, | ||
| ) -> "Optional[Union[Span, StreamedSpan]]": | ||
| """ | ||
|
|
@@ -68,14 +69,14 @@ | |
| span = getattr(context_wrapper, "_sentry_agent_span", None) | ||
| if span: | ||
| update_invoke_agent_span( | ||
| span=span, context=context_wrapper, agent=agent | ||
| span=span, usage=context_wrapper.usage, agent=agent | ||
| ) | ||
| span.__exit__(None, None, None) | ||
| delattr(context_wrapper, "_sentry_agent_span") | ||
|
|
||
| # Store the agent on the context wrapper so we can access it later | ||
| context_wrapper._sentry_current_agent = agent | ||
| span = invoke_agent_span(context_wrapper, agent, span_kwargs) | ||
| span = invoke_agent_span(agent, turn_input) | ||
| context_wrapper._sentry_agent_span = span | ||
| agent._sentry_agent_span = span | ||
|
|
||
|
|
@@ -92,6 +93,7 @@ | |
|
|
||
| async def _run_single_turn( | ||
| original_run_single_turn: "Callable[..., Awaitable[SingleStepResult]]", | ||
| use_run_hooks: "bool", | ||
| *args: "Any", | ||
| **kwargs: "Any", | ||
| ) -> "SingleStepResult": | ||
|
|
@@ -107,39 +109,56 @@ | |
| if bindings is not None | ||
| else kwargs.get("agent") | ||
| ) | ||
| context_wrapper = kwargs.get("context_wrapper") | ||
| should_run_agent_start_hooks = kwargs.get("should_run_agent_start_hooks", False) | ||
|
|
||
| span = _maybe_start_agent_span( | ||
| context_wrapper, agent, should_run_agent_start_hooks, kwargs | ||
| ) | ||
| context_wrapper: "agents.RunContextWrapper[Any]" = kwargs.get("context_wrapper") | ||
| if not use_run_hooks: | ||
| should_run_agent_start_hooks = kwargs.get("should_run_agent_start_hooks", False) | ||
|
|
||
| if ( | ||
| span is None | ||
| or (isinstance(span, StreamedSpan) and span.end_timestamp is not None) | ||
| or (not isinstance(span, StreamedSpan) and span.timestamp is not None) | ||
| ): | ||
| return await original_run_single_turn(*args, **kwargs) | ||
| span = _maybe_start_agent_span( | ||
| context_wrapper, | ||
| agent, | ||
| should_run_agent_start_hooks, | ||
| kwargs.get("input"), | ||
| ) | ||
|
|
||
| if ( | ||
| span is None | ||
| or (isinstance(span, StreamedSpan) and span.end_timestamp is not None) | ||
| or (not isinstance(span, StreamedSpan) and span.timestamp is not None) | ||
| ): | ||
| return await original_run_single_turn(*args, **kwargs) | ||
|
|
||
| try: | ||
| result = await original_run_single_turn(*args, **kwargs) | ||
| except Exception: | ||
| exc_info = sys.exc_info() | ||
| with capture_internal_exceptions(): | ||
| span = getattr(context_wrapper, "_sentry_agent_span", None) | ||
| if span: | ||
| update_invoke_agent_span( | ||
| span=span, context=context_wrapper, agent=agent | ||
| ) | ||
| span.__exit__(*exc_info) | ||
| delattr(context_wrapper, "_sentry_agent_span") | ||
| if use_run_hooks: | ||
| run_hooks = kwargs.get("hooks") | ||
| if run_hooks is not None: | ||
| span = getattr(run_hooks, "_sentry_invoke_agent_span", None) | ||
|
Check failure on line 139 in sentry_sdk/integrations/openai_agents/patches/agent_run.py
|
||
| if span is not None: | ||
| update_invoke_agent_span( | ||
| span=span, usage=context_wrapper.usage, agent=agent | ||
| ) | ||
| del run_hooks._sentry_invoke_agent_span | ||
| span.__exit__(*exc_info) | ||
| else: | ||
| span = getattr(context_wrapper, "_sentry_agent_span", None) | ||
| if span: | ||
| update_invoke_agent_span( | ||
| span=span, usage=context_wrapper.usage, agent=agent | ||
| ) | ||
| span.__exit__(*exc_info) | ||
| delattr(context_wrapper, "_sentry_agent_span") | ||
| reraise(*exc_info) | ||
|
|
||
| return result | ||
|
|
||
|
|
||
| async def _run_single_turn_streamed( | ||
| original_run_single_turn_streamed: "Callable[..., Awaitable[SingleStepResult]]", | ||
| use_run_hooks: "bool", | ||
| *args: "Any", | ||
| **kwargs: "Any", | ||
| ) -> "SingleStepResult": | ||
|
|
@@ -181,42 +200,59 @@ | |
| args[1] if len(args) > 1 else kwargs.get("bindings", kwargs.get("agent")) | ||
| ) | ||
| agent = getattr(agent_or_bindings, "public_agent", agent_or_bindings) | ||
| context_wrapper = args[3] if len(args) > 3 else kwargs.get("context_wrapper") | ||
| should_run_agent_start_hooks = bool( | ||
| args[5] if len(args) > 5 else kwargs.get("should_run_agent_start_hooks", False) | ||
|
|
||
| context_wrapper: "agents.RunContextWrapper[Any]" = ( | ||
| args[3] if len(args) > 3 else kwargs.get("context_wrapper") | ||
| ) | ||
| if not use_run_hooks: | ||
| should_run_agent_start_hooks = bool( | ||
| args[5] | ||
| if len(args) > 5 | ||
| else kwargs.get("should_run_agent_start_hooks", False) | ||
| ) | ||
|
|
||
| span_kwargs: "dict[str, Any]" = {} | ||
| if streamed_result and hasattr(streamed_result, "input"): | ||
| span_kwargs["original_input"] = streamed_result.input | ||
| span_kwargs: "dict[str, Any]" = {} | ||
| if streamed_result and hasattr(streamed_result, "input"): | ||
| span_kwargs["original_input"] = streamed_result.input | ||
|
|
||
| span = _maybe_start_agent_span( | ||
| context_wrapper, | ||
| agent, | ||
| should_run_agent_start_hooks, | ||
| span_kwargs, | ||
| is_streaming=True, | ||
| ) | ||
| span = _maybe_start_agent_span( | ||
| context_wrapper, | ||
| agent, | ||
| should_run_agent_start_hooks, | ||
| getattr(streamed_result, "input", None), | ||
| is_streaming=True, | ||
| ) | ||
|
|
||
| if ( | ||
| span is None | ||
| or (isinstance(span, StreamedSpan) and span.end_timestamp is not None) | ||
| or (not isinstance(span, StreamedSpan) and span.timestamp is not None) | ||
| ): | ||
| return await original_run_single_turn_streamed(*args, **kwargs) | ||
| if ( | ||
| span is None | ||
| or (isinstance(span, StreamedSpan) and span.end_timestamp is not None) | ||
| or (not isinstance(span, StreamedSpan) and span.timestamp is not None) | ||
| ): | ||
| return await original_run_single_turn_streamed(*args, **kwargs) | ||
|
|
||
| try: | ||
| result = await original_run_single_turn_streamed(*args, **kwargs) | ||
| except Exception: | ||
| exc_info = sys.exc_info() | ||
| with capture_internal_exceptions(): | ||
| span = getattr(context_wrapper, "_sentry_agent_span", None) | ||
| if span: | ||
| update_invoke_agent_span( | ||
| span=span, context=context_wrapper, agent=agent | ||
| ) | ||
| span.__exit__(*exc_info) | ||
| delattr(context_wrapper, "_sentry_agent_span") | ||
| if use_run_hooks: | ||
| run_hooks = args[2] if len(args) > 2 else kwargs.get("hooks") | ||
| if run_hooks is not None: | ||
| span = getattr(run_hooks, "_sentry_invoke_agent_span", None) | ||
| if span is not None: | ||
| update_invoke_agent_span( | ||
| span=span, usage=context_wrapper.usage, agent=agent | ||
| ) | ||
| del run_hooks._sentry_invoke_agent_span | ||
| span.__exit__(*exc_info) | ||
| else: | ||
|
Check failure on line 248 in sentry_sdk/integrations/openai_agents/patches/agent_run.py
|
||
| span = getattr(context_wrapper, "_sentry_agent_span", None) | ||
| if span: | ||
|
Check failure on line 250 in sentry_sdk/integrations/openai_agents/patches/agent_run.py
|
||
|
Comment on lines
+242
to
+250
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invoke agent span leaks on exception when user-provided hooks are used The exception handler retrieves Evidence
Also found at 2 additional locations
Identified by Warden · find-bugs · XD7-X2Q |
||
| update_invoke_agent_span( | ||
| span=span, usage=context_wrapper.usage, agent=agent | ||
| ) | ||
| span.__exit__(*exc_info) | ||
| delattr(context_wrapper, "_sentry_agent_span") | ||
| _close_streaming_workflow_span(agent) | ||
| reraise(*exc_info) | ||
|
|
||
|
|
@@ -266,15 +302,15 @@ | |
| span = getattr(context_wrapper, "_sentry_agent_span", None) | ||
| if span: | ||
| update_invoke_agent_span( | ||
| span=span, context=context_wrapper, agent=agent | ||
| span=span, usage=context_wrapper.usage, agent=agent | ||
| ) | ||
| span.__exit__(*exc_info) | ||
| delattr(context_wrapper, "_sentry_agent_span") | ||
| reraise(*exc_info) | ||
|
|
||
| span = getattr(context_wrapper, "_sentry_agent_span", None) | ||
| if span: | ||
| update_invoke_agent_span(span=span, context=context_wrapper, agent=agent) | ||
| update_invoke_agent_span(span=span, usage=context_wrapper.usage, agent=agent) | ||
| span.__exit__(None, None, None) | ||
| delattr(context_wrapper, "_sentry_agent_span") | ||
|
|
||
|
|
@@ -315,7 +351,10 @@ | |
| span = getattr(context_wrapper, "_sentry_agent_span", None) | ||
| if span: | ||
| update_invoke_agent_span( | ||
| span=span, context=context_wrapper, agent=agent, output=final_output | ||
| span=span, | ||
| usage=context_wrapper.usage, | ||
| agent=agent, | ||
| output=final_output, | ||
| ) | ||
| span.__exit__(*exc_info) | ||
| delattr(context_wrapper, "_sentry_agent_span") | ||
|
|
@@ -324,7 +363,7 @@ | |
| span = getattr(context_wrapper, "_sentry_agent_span", None) | ||
| if span: | ||
| update_invoke_agent_span( | ||
| span=span, context=context_wrapper, agent=agent, output=final_output | ||
| span=span, usage=context_wrapper.usage, agent=agent, output=final_output | ||
| ) | ||
| span.__exit__(None, None, None) | ||
| delattr(context_wrapper, "_sentry_agent_span") | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.