Skip to content

ref(openai-agents): Use first class agent hooks when available - #7029

Open
alexander-alderman-webb wants to merge 38 commits into
masterfrom
webb/use-agent-hooks-2
Open

ref(openai-agents): Use first class agent hooks when available#7029
alexander-alderman-webb wants to merge 38 commits into
masterfrom
webb/use-agent-hooks-2

Conversation

@alexander-alderman-webb

@alexander-alderman-webb alexander-alderman-webb commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

Add on_agent_start(), on_agent_end() and on_handoff() hooks.

Unlike tool hooks, the Invoke Agent span is stored on the RunHooks instance.

If the hooks are active, start and finish Invoke Agent spans in the hooks in successful executions. If an exception bubbles up, on_agent_end() does not run. Modify monkey-patches so that the span stored on the RunHooks instance is finished if the hooks are present.

Make the signatures of invoke_agent_span(), update_invoke_agent_span() and _maybe_start_agent_span() more minimal so that they can be re-used in the on_agent_start() and on_agent_end() hooks.

Issues

Closes #6989

Reminders

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Codecov Results 📊

99162 passed | ⏭️ 6479 skipped | Total: 105641 | Pass Rate: 93.87% | Execution Time: 353m 35s

📊 Comparison with Base Branch

Metric Change
Total Tests 📈 +60
Passed Tests 📈 +60
Failed Tests
Skipped Tests

All tests are passing successfully.

✅ Patch coverage is 89.11%. Project has 2500 uncovered lines.
✅ Project coverage is 90.01%. Comparing base (base) to head (head).

Files with missing lines (3)
File Patch % Lines
sentry_sdk/integrations/openai_agents/patches/runner.py 82.35% ⚠️ 9 Missing and 5 partials
sentry_sdk/integrations/openai_agents/patches/agent_run.py 95.56% ⚠️ 2 Missing and 9 partials
sentry_sdk/integrations/openai_agents/spans/invoke_agent.py 100.00% ⚠️ 1 partials
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    89.96%    90.01%    +0.05%
==========================================
  Files          193       193         —
  Lines        24954     25015       +61
  Branches      9004      9030       +26
==========================================
+ Hits         22448     22515       +67
- Misses        2506      2500        -6
- Partials      1434      1439        +5

Generated by Codecov Action

@alexander-alderman-webb
alexander-alderman-webb changed the base branch from webb/use-agent-hooks to webb/fix-run_single_turn_streamed-patch August 4, 2026 13:09
@alexander-alderman-webb
alexander-alderman-webb marked this pull request as ready for review August 4, 2026 15:09
@alexander-alderman-webb
alexander-alderman-webb requested a review from a team as a code owner August 4, 2026 15:09
Comment thread sentry_sdk/integrations/openai_agents/patches/runner.py
Comment thread sentry_sdk/integrations/openai_agents/patches/runner.py
Comment thread sentry_sdk/integrations/openai_agents/patches/runner.py
Comment thread sentry_sdk/integrations/openai_agents/patches/agent_run.py Outdated
@alexander-alderman-webb
alexander-alderman-webb marked this pull request as draft August 4, 2026 15:33
Comment thread sentry_sdk/integrations/openai_agents/patches/agent_run.py
Comment thread sentry_sdk/integrations/openai_agents/patches/agent_run.py
Comment thread sentry_sdk/integrations/openai_agents/spans/invoke_agent.py
@alexander-alderman-webb
alexander-alderman-webb marked this pull request as ready for review August 5, 2026 14:03
Comment thread sentry_sdk/integrations/openai_agents/patches/agent_run.py
Comment thread sentry_sdk/integrations/openai_agents/patches/runner.py Outdated
Comment thread sentry_sdk/integrations/openai_agents/patches/agent_run.py
Comment thread sentry_sdk/integrations/openai_agents/patches/runner.py Outdated
Comment thread sentry_sdk/integrations/openai_agents/patches/runner.py
Comment on lines +136 to +138
if use_run_hooks:
run_hooks = kwargs.get("hooks")
if run_hooks is not None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To confirm my understanding of what's happening here - are run hooks something that are passed in by users (which is why they could potentially be None)?

and `on_tool_end()`
Responsible for creating Execute Tool and Invoke Agent spans. Both
spans can also be closed by hooks, and Execute Tool spans are exclusively
closed in the hook.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say "the hook" here - is there are specific hook that you're referring to? Or do you mean this as just a generalized "run hook"?

Base automatically changed from webb/fix-run_single_turn_streamed-patch to master August 6, 2026 07:39
Comment on lines +279 to +282
update_invoke_agent_span(
span=invoke_agent_span,
usage=context_wrapper.usage,
agent=agent,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: In _create_run_wrapper, if no hooks are provided, the local hooks variable remains None. The exception handler then fails to access the span, causing a span leak on AgentsException.
Severity: MEDIUM

Suggested Fix

In the exception handler within _create_run_wrapper, access the hooks instance from kwargs.get("hooks") instead of the local hooks variable. Alternatively, ensure the local hooks variable is updated when a new _SentryRunHooks instance is created and added to kwargs.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: sentry_sdk/integrations/openai_agents/patches/runner.py#L279-L282

Potential issue: When `agents.Runner.run()` is called without a `hooks` parameter and
`use_run_hooks` is true, a new `_SentryRunHooks` instance is created and stored in
`kwargs["hooks"]`. However, a local `hooks` variable remains `None`. If an
`AgentsException` is raised, the exception handler attempts to retrieve a span from the
local `hooks` variable. Since it's `None`, `getattr(hooks, "_sentry_invoke_agent_span",
None)` returns `None`, and the span created in `on_agent_start` is never closed, leading
to a span leak. The `capture_internal_exceptions` context manager suppresses the
potential `AttributeError`, hiding the issue.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 327a4d8. Configure here.

)

invoke_agent_span.__exit__(None, None, None)
delattr(run_result.context_wrapper, "_sentry_agent_span")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default hooks left unbound

Medium Severity

When no user hooks are provided, a new _SentryRunHooks is assigned only to kwargs["hooks"], while the local hooks variable stays None. The AgentsException cleanup path then cannot find or finish the active invoke-agent span.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 327a4d8. Configure here.

) -> "SingleStepResult":
return await _execute_handoffs(original_execute_handoffs, *args, **kwargs)
return await _execute_handoffs(
original_execute_handoffs, use_run_hooks, *args, **kwargs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exception in _execute_handoffs leaks invoke agent span when hooks are active

In patches/agent_run.py, _execute_handoffs has an early-return path when use_run_hooks is true. The except Exception block on that path only calls _close_streaming_workflow_span(agent); it never finishes the _sentry_invoke_agent_span stored on run_hooks. This is inconsistent with _run_single_turn and _run_single_turn_streamed, whose exception handlers both explicitly look up run_hooks._sentry_invoke_agent_span and finish it when use_run_hooks=True.

Evidence
  • patches/agent_run.py line 288: _execute_handoffs enters an early-return path when use_run_hooks=True.
  • Line 295: the except Exception block in that path only calls _close_streaming_workflow_span(agent).
  • It never accesses kwargs.get("hooks") or finishes run_hooks._sentry_invoke_agent_span.
  • By contrast, _run_single_turn (line 133) and _run_single_turn_streamed (line 235) each have except Exception logic that looks up run_hooks._sentry_invoke_agent_span and finishes it when use_run_hooks=True.

Identified by Warden · code-review · CJL-QQK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use RunHooks.on_agent_start and RunHooks.on_agent_end

2 participants