Skip to content

Commit 5a8f060

Browse files
docs: Document openai-agents control-flow (#5447)
1 parent 77035cc commit 5a8f060

File tree

5 files changed

+59
-6
lines changed

5 files changed

+59
-6
lines changed

sentry_sdk/integrations/openai_agents/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,32 @@ def _patch_tools() -> None:
5252

5353

5454
class OpenAIAgentsIntegration(Integration):
55+
"""
56+
NOTE: With version 0.8.0, the class methods below have been refactored to functions.
57+
- `AgentRunner._get_model()` -> `agents.run_internal.turn_preparation.get_model()`
58+
- `AgentRunner._get_all_tools()` -> `agents.run_internal.turn_preparation.get_all_tools()`
59+
- `AgentRunner._run_single_turn()` -> `agents.run_internal.run_loop.run_single_turn()`
60+
- `RunImpl.execute_handoffs()` -> `agents.run_internal.turn_resolution.execute_handoffs()`
61+
- `RunImpl.execute_final_output()` -> `agents.run_internal.turn_resolution.execute_final_output()`
62+
63+
Typical interaction with the library:
64+
1. The user creates an Agent instance with configuration, including system instructions sent to every Responses API call.
65+
2. The user passes the agent instance to a Runner with `run()` and `run_streamed()` methods. The latter can be used to incrementally receive progress.
66+
- `Runner.run()` and `Runner.run_streamed()` are thin wrappers for `DEFAULT_AGENT_RUNNER.run()` and `DEFAULT_AGENT_RUNNER.run_streamed()`.
67+
- `DEFAULT_AGENT_RUNNER.run()` and `DEFAULT_AGENT_RUNNER.run_streamed()` are patched in `_patch_runner()` with `_create_run_wrapper()` and `_create_run_streamed_wrapper()`, respectively.
68+
3. In a loop, the agent repeatedly calls the Responses API, maintaining a conversation history that includes previous messages and tool results, which is passed to each call.
69+
- A Model instance is created at the start of the loop by calling the `Runner._get_model()`. We patch the Model instance using `_create_get_model_wrapper()` in `_patch_model()`.
70+
- Available tools are also deteremined at the start of the loop, with `Runner._get_all_tools()`. We patch Tool instances by iterating through the returned tools, in `_create_get_all_tools_wrapper()` called via `_patch_tools()`
71+
- In each loop iteration, `run_single_turn()` or `run_single_turn_streamed()` is responsible for calling the Responses API, patched with `patched_run_single_turn()` and `patched_run_single_turn_streamed()`.
72+
4. On loop termination, `RunImpl.execute_final_output()` is called. The function is patched with `patched_execute_final_output()`.
73+
74+
Local tools are run based on the return value from the Responses API as a post-API call step in the above loop.
75+
Hosted MCP Tools are run as part of the Responses API call, and involve OpenAI reaching out to an external MCP server.
76+
An agent can handoff to another agent, also directed by the return value of the Responses API and run post-API call in the loop.
77+
Handoffs are a way to switch agent-wide configuration.
78+
- Handoffs are executed by calling `RunImpl.execute_handoffs()`. The method is patched in `patched_execute_handoffs()`
79+
"""
80+
5581
identifier = "openai_agents"
5682

5783
@staticmethod

sentry_sdk/integrations/openai_agents/patches/agent_run.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@ def _maybe_start_agent_span(
9494
async def patched_run_single_turn(
9595
cls: "agents.Runner", *args: "Any", **kwargs: "Any"
9696
) -> "Any":
97-
"""Patched _run_single_turn that creates agent invocation spans"""
97+
"""
98+
Patched _run_single_turn that
99+
- creates agent invocation spans if there is no already active agent invocation span.
100+
- ends the agent invocation span if and only if an exception is raised in `_run_single_turn()`.
101+
"""
98102
agent = kwargs.get("agent")
99103
context_wrapper = kwargs.get("context_wrapper")
100104
should_run_agent_start_hooks = kwargs.get("should_run_agent_start_hooks", False)
@@ -121,7 +125,12 @@ async def patched_run_single_turn(
121125
async def patched_execute_handoffs(
122126
cls: "agents.Runner", *args: "Any", **kwargs: "Any"
123127
) -> "Any":
124-
"""Patched execute_handoffs that creates handoff spans and ends agent span for handoffs"""
128+
"""
129+
Patched execute_handoffs that
130+
- creates and manages handoff spans.
131+
- ends the agent invocation span.
132+
- ends the workflow span if the response is streamed and an exception is raised in `execute_handoffs()`.
133+
"""
125134

126135
context_wrapper = kwargs.get("context_wrapper")
127136
run_handoffs = kwargs.get("run_handoffs")
@@ -156,7 +165,11 @@ async def patched_execute_handoffs(
156165
async def patched_execute_final_output(
157166
cls: "agents.Runner", *args: "Any", **kwargs: "Any"
158167
) -> "Any":
159-
"""Patched execute_final_output that ends agent span for final outputs"""
168+
"""
169+
Patched execute_final_output that
170+
- ends the agent invocation span.
171+
- ends the workflow span if the response is streamed.
172+
"""
160173

161174
agent = kwargs.get("agent")
162175
context_wrapper = kwargs.get("context_wrapper")
@@ -185,7 +198,10 @@ async def patched_execute_final_output(
185198
async def patched_run_single_turn_streamed(
186199
cls: "agents.Runner", *args: "Any", **kwargs: "Any"
187200
) -> "Any":
188-
"""Patched _run_single_turn_streamed that creates agent invocation spans for streaming.
201+
"""
202+
Patched _run_single_turn_streamed that
203+
- creates agent invocation spans for streaming if there is no already active agent invocation span.
204+
- ends the agent invocation span if and only if `_run_single_turn_streamed()` raises an exception.
189205
190206
Note: Unlike _run_single_turn which uses keyword-only arguments (*,),
191207
_run_single_turn_streamed uses positional arguments. The call signature is:

sentry_sdk/integrations/openai_agents/patches/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ def _create_get_model_wrapper(
7171
) -> "Callable[..., Any]":
7272
"""
7373
Wraps the agents.Runner._get_model method to wrap the get_response method of the model to create a AI client span.
74+
75+
Responsible for
76+
- creating and managing AI client spans.
77+
- adding trace propagation headers to tools with type HostedMCPTool.
78+
- setting the response model on agent invocation spans.
7479
"""
7580

7681
@wraps(

sentry_sdk/integrations/openai_agents/patches/runner.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222

2323
def _create_run_wrapper(original_func: "Callable[..., Any]") -> "Callable[..., Any]":
2424
"""
25-
Wraps the agents.Runner.run methods to create a root span for the agent workflow runs.
25+
Wraps the agents.Runner.run methods to
26+
- create and manage a root span for the agent workflow runs.
27+
- end the agent invocation span if an `AgentsException` is raised in `run()`.
2628
2729
Note agents.Runner.run_sync() is a wrapper around agents.Runner.run(),
2830
so it does not need to be wrapped separately.
@@ -85,7 +87,9 @@ def _create_run_streamed_wrapper(
8587
original_func: "Callable[..., Any]",
8688
) -> "Callable[..., Any]":
8789
"""
88-
Wraps the agents.Runner.run_streamed method to create a root span for streaming agent workflow runs.
90+
Wraps the agents.Runner.run_streamed method to
91+
- create a root span for streaming agent workflow runs.
92+
- end the workflow span if and only if the response stream is consumed or cancelled.
8993
9094
Unlike run(), run_streamed() returns immediately with a RunResultStreaming object
9195
while execution continues in a background task. The workflow span must stay open

sentry_sdk/integrations/openai_agents/patches/tools.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ def _create_get_all_tools_wrapper(
1919
original_get_all_tools: "Callable[..., Any]",
2020
) -> "Callable[..., Any]":
2121
"""
22+
Responsible for creating and managing `gen_ai.execute_tool` spans.
23+
2224
Wraps the agents.Runner._get_all_tools method of the Runner class to wrap all function tools with Sentry instrumentation.
2325
"""
2426

0 commit comments

Comments
 (0)