Skip to content

Commit 34111be

Browse files
ericapisaniclaude
andauthored
fix(openai-agents): Resolve agent from bindings for openai-agents >= 0.14 (#6102)
Update the openai-agents integration's run-loop patches to resolve the current agent from the new `AgentBindings` dataclass introduced in openai-agents 0.14, falling back to the pre-0.14 `agent` kwarg. Prior to 0.14, `run_single_turn`, `run_single_turn_streamed`, `execute_handoffs`, and `execute_final_output` all received the current agent as `agent=...`. In 0.14 the library refactored these to pass `bindings: AgentBindings` (carrying `public_agent` and `execution_agent`) to the `run_single_turn*` functions and renamed the `agent` kwarg to `public_agent` on the `execute_*` functions. Our patches still called `kwargs.get("agent")`, which returned `None` — so `_maybe_start_agent_span` short-circuited and no `invoke_agent` span was ever created. Every `test_agent_invocation_span*` parametrization failed on the `openai_agents-latest` suite with `not enough values to unpack (expected 2, got 1)`. `public_agent` is used rather than `execution_agent` because it's the user-facing identity the library itself uses for lifecycle hooks (`on_agent_start`, `on_llm_start`), `streamed_result.current_agent`, and `RunItem.agent` fields. The two only diverge in sandbox execution (`agents/sandbox/runtime.py`), where `execution_agent` is a cloned sandbox-prepared agent — using that would produce unstable span names that don't match what users see from the library's own callbacks. Verified locally against `py3.14-openai_agents-latest` (bindings path) and `py3.14-openai_agents-v0.8.4` (legacy kwarg fallback path). Refs PY-2382 Fixes #6101 Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent a594f8b commit 34111be

1 file changed

Lines changed: 30 additions & 5 deletions

File tree

sentry_sdk/integrations/openai_agents/patches/agent_run.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,13 @@ async def _run_single_turn(
8989
- creates agent invocation spans if there is no already active agent invocation span.
9090
- ends the agent invocation span if and only if an exception is raised in `_run_single_turn()`.
9191
"""
92-
agent = kwargs.get("agent")
92+
# openai-agents >= 0.14 passes `bindings: AgentBindings` instead of `agent`.
93+
bindings = kwargs.get("bindings")
94+
agent = (
95+
getattr(bindings, "public_agent", None)
96+
if bindings is not None
97+
else kwargs.get("agent")
98+
)
9399
context_wrapper = kwargs.get("context_wrapper")
94100
should_run_agent_start_hooks = kwargs.get("should_run_agent_start_hooks", False)
95101

@@ -119,7 +125,7 @@ async def _run_single_turn_streamed(
119125
- ends the agent invocation span if and only if `_run_single_turn_streamed()` raises an exception.
120126
121127
Note: Unlike _run_single_turn which uses keyword-only arguments (*,),
122-
_run_single_turn_streamed uses positional arguments. The call signature is:
128+
_run_single_turn_streamed uses positional arguments. The call signature <v0.14 is:
123129
_run_single_turn_streamed(
124130
streamed_result, # args[0]
125131
agent, # args[1]
@@ -131,9 +137,26 @@ async def _run_single_turn_streamed(
131137
all_tools, # args[7]
132138
server_conversation_tracker, # args[8] (optional)
133139
)
140+
141+
The call signature >=v0.14 is:
142+
_run_single_turn_streamed(
143+
streamed_result, # args[0]
144+
bindings, # args[1]
145+
hooks, # args[2]
146+
context_wrapper, # args[3]
147+
run_config, # args[4]
148+
should_run_agent_start_hooks, # args[5]
149+
tool_use_tracker, # args[6]
150+
all_tools, # args[7]
151+
server_conversation_tracker, # args[8] (optional)
152+
)
134153
"""
135154
streamed_result = args[0] if len(args) > 0 else kwargs.get("streamed_result")
136-
agent = args[1] if len(args) > 1 else kwargs.get("agent")
155+
# openai-agents >= 0.14 passes `bindings: AgentBindings` at args[1] instead of `agent`.
156+
agent_or_bindings = (
157+
args[1] if len(args) > 1 else kwargs.get("bindings", kwargs.get("agent"))
158+
)
159+
agent = getattr(agent_or_bindings, "public_agent", agent_or_bindings)
137160
context_wrapper = args[3] if len(args) > 3 else kwargs.get("context_wrapper")
138161
should_run_agent_start_hooks = bool(
139162
args[5] if len(args) > 5 else kwargs.get("should_run_agent_start_hooks", False)
@@ -179,7 +202,8 @@ async def _execute_handoffs(
179202

180203
context_wrapper = kwargs.get("context_wrapper")
181204
run_handoffs = kwargs.get("run_handoffs")
182-
agent = kwargs.get("agent")
205+
# openai-agents >= 0.14 renamed `agent` to `public_agent`.
206+
agent = kwargs.get("public_agent", kwargs.get("agent"))
183207

184208
# Create Sentry handoff span for the first handoff (agents library only processes the first one)
185209
if run_handoffs:
@@ -214,7 +238,8 @@ async def _execute_final_output(
214238
- ends the workflow span if the response is streamed.
215239
"""
216240

217-
agent = kwargs.get("agent")
241+
# openai-agents >= 0.14 renamed `agent` to `public_agent`.
242+
agent = kwargs.get("public_agent", kwargs.get("agent"))
218243
context_wrapper = kwargs.get("context_wrapper")
219244
final_output = kwargs.get("final_output")
220245

0 commit comments

Comments
 (0)