Skip to content

Commit c741020

Browse files
committed
Merge branch 'master' into feat/span-first-2
2 parents 4dcd106 + dd0feec commit c741020

13 files changed

Lines changed: 698 additions & 555 deletions

File tree

.github/workflows/test-integrations-dbs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ jobs:
6666
python-version: ${{ matrix.python-version }}
6767
allow-prereleases: true
6868
- name: "Setup ClickHouse Server"
69-
uses: getsentry/action-clickhouse-in-ci@v1.6
69+
uses: getsentry/action-clickhouse-in-ci@v1.7
7070
- name: Setup Test Env
7171
run: |
7272
pip install "coverage[toml]" tox

CHANGELOG.md

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,42 @@
22

33
## 2.52.0a5
44

5+
This is an alpha release for internal testing of span streaming.
6+
7+
## 2.53.0
8+
9+
### Bug Fixes 🐛
10+
11+
#### Openai Agents
12+
13+
- Patch `execute_final_output()` functions following library refactor by @alexander-alderman-webb in [#5453](https://github.com/getsentry/sentry-python/pull/5453)
14+
- Patch `execute_handoffs()` functions following library refactor by @alexander-alderman-webb in [#5452](https://github.com/getsentry/sentry-python/pull/5452)
15+
- Patch `run_single_turn_streamed()` functions following library refactor by @alexander-alderman-webb in [#5451](https://github.com/getsentry/sentry-python/pull/5451)
16+
- Patch `run_single_turn()` functions following library refactor by @alexander-alderman-webb in [#5450](https://github.com/getsentry/sentry-python/pull/5450)
17+
- Patch models functions following library refactor by @alexander-alderman-webb in [#5449](https://github.com/getsentry/sentry-python/pull/5449)
18+
- Patch tool functions following library refactor by @alexander-alderman-webb in [#5445](https://github.com/getsentry/sentry-python/pull/5445)
19+
20+
#### Other
21+
22+
- Close the connection we're reading driver_type from by @sentrivana in [#5427](https://github.com/getsentry/sentry-python/pull/5427)
23+
524
### Documentation 📚
625

726
- Document `openai-agents` control-flow by @alexander-alderman-webb in [#5447](https://github.com/getsentry/sentry-python/pull/5447)
827

928
### Internal Changes 🔧
1029

11-
- (ci) Improve Craft config with title stripping and artifact filtering by @BYK in [#5444](https://github.com/getsentry/sentry-python/pull/5444)
12-
- (openai-agents) Avoid calling SDK-internal functions by @alexander-alderman-webb in [#5437](https://github.com/getsentry/sentry-python/pull/5437)
13-
- Remove references to unsupported attribute types by @alexander-alderman-webb in [#5425](https://github.com/getsentry/sentry-python/pull/5425)
30+
#### Openai Agents
1431

15-
### Other
32+
- New tool field and library error log by @alexander-alderman-webb in [#5454](https://github.com/getsentry/sentry-python/pull/5454)
33+
- Avoid calling SDK-internal functions by @alexander-alderman-webb in [#5437](https://github.com/getsentry/sentry-python/pull/5437)
1634

17-
- [do not merge] feat: Span streaming & new span API by @sentrivana in [#5317](https://github.com/getsentry/sentry-python/pull/5317)
35+
#### Other
36+
37+
- Improve Craft config with title stripping and artifact filtering by @BYK in [#5444](https://github.com/getsentry/sentry-python/pull/5444)
38+
- Use fixed clickhouse action, remove aws-sam-cli dependency by @sentrivana in [#5457](https://github.com/getsentry/sentry-python/pull/5457)
39+
- Remove references to unsupported attribute types by @alexander-alderman-webb in [#5425](https://github.com/getsentry/sentry-python/pull/5425)
40+
- Pin setuptools for linting and chalice tests by @alexander-alderman-webb in [#5438](https://github.com/getsentry/sentry-python/pull/5438)
1841

1942
## 2.52.0a4
2043

scripts/populate_tox/package_dependencies.jsonl

Lines changed: 25 additions & 24 deletions
Large diffs are not rendered by default.

scripts/populate_tox/releases.jsonl

Lines changed: 26 additions & 25 deletions
Large diffs are not rendered by default.

scripts/populate_tox/tox.jinja

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ deps =
112112
113113
# AWS Lambda
114114
aws_lambda: aws-cdk-lib
115-
aws_lambda: aws-sam-cli
116115
aws_lambda: boto3
117116
aws_lambda: fastapi
118117
aws_lambda: requests

scripts/split_tox_gh_actions/templates/test_group.jinja

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
{% if needs_clickhouse %}
5353
- name: "Setup ClickHouse Server"
54-
uses: getsentry/action-clickhouse-in-ci@v1.6
54+
uses: getsentry/action-clickhouse-in-ci@v1.7
5555
{% endif %}
5656

5757
{% if needs_redis %}
Lines changed: 180 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
from sentry_sdk.integrations import DidNotEnable, Integration
2+
from sentry_sdk.utils import parse_version
3+
4+
from functools import wraps
25

36
from .patches import (
4-
_create_get_model_wrapper,
5-
_create_get_all_tools_wrapper,
7+
_get_model,
8+
_get_all_tools,
9+
_run_single_turn,
10+
_run_single_turn_streamed,
11+
_execute_handoffs,
612
_create_run_wrapper,
713
_create_run_streamed_wrapper,
8-
_patch_agent_run,
14+
_execute_final_output,
915
_patch_error_tracing,
1016
)
1117

@@ -17,11 +23,30 @@
1723
# after it, even if we don't use it.
1824
import agents
1925
from agents.run import DEFAULT_AGENT_RUNNER
26+
from agents.run import AgentRunner
27+
from agents.version import __version__ as OPENAI_AGENTS_VERSION
2028

2129
except ImportError:
2230
raise DidNotEnable("OpenAI Agents not installed")
2331

2432

33+
try:
34+
# AgentRunner methods moved in v0.8
35+
# https://github.com/openai/openai-agents-python/commit/3ce7c24d349b77bb750062b7e0e856d9ff48a5d5#diff-7470b3a5c5cbe2fcbb2703dc24f326f45a5819d853be2b1f395d122d278cd911
36+
from agents.run_internal import run_loop, turn_preparation, turn_resolution
37+
except ImportError:
38+
run_loop = None
39+
turn_preparation = None
40+
turn_resolution = None
41+
42+
from typing import TYPE_CHECKING
43+
44+
if TYPE_CHECKING:
45+
from typing import Any
46+
47+
from agents.run_internal.run_steps import SingleStepResult
48+
49+
2550
def _patch_runner() -> None:
2651
# Create the root span for one full agent run (including eventual handoffs)
2752
# Note agents.run.DEFAULT_AGENT_RUNNER.run_sync is a wrapper around
@@ -35,21 +60,6 @@ def _patch_runner() -> None:
3560
agents.run.DEFAULT_AGENT_RUNNER.run_streamed
3661
)
3762

38-
# Creating the actual spans for each agent run (works for both streaming and non-streaming).
39-
_patch_agent_run()
40-
41-
42-
def _patch_model() -> None:
43-
agents.run.AgentRunner._get_model = classmethod(
44-
_create_get_model_wrapper(agents.run.AgentRunner._get_model),
45-
)
46-
47-
48-
def _patch_tools() -> None:
49-
agents.run.AgentRunner._get_all_tools = classmethod(
50-
_create_get_all_tools_wrapper(agents.run.AgentRunner._get_all_tools),
51-
)
52-
5363

5464
class OpenAIAgentsIntegration(Integration):
5565
"""
@@ -66,23 +76,168 @@ class OpenAIAgentsIntegration(Integration):
6676
- `Runner.run()` and `Runner.run_streamed()` are thin wrappers for `DEFAULT_AGENT_RUNNER.run()` and `DEFAULT_AGENT_RUNNER.run_streamed()`.
6777
- `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.
6878
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()`.
79+
- A Model instance is created at the start of the loop by calling the `Runner._get_model()`. We patch the Model instance using `patches._get_model()`.
80+
- 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 `patches._get_all_tools()`.
81+
- In each loop iteration, `run_single_turn()` or `run_single_turn_streamed()` is responsible for calling the Responses API, patched with `patches._run_single_turn()` and `patches._run_single_turn_streamed()`.
82+
4. On loop termination, `RunImpl.execute_final_output()` is called. The function is patched with `patches._execute_final_output()`.
7383
7484
Local tools are run based on the return value from the Responses API as a post-API call step in the above loop.
7585
Hosted MCP Tools are run as part of the Responses API call, and involve OpenAI reaching out to an external MCP server.
7686
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.
7787
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()`
88+
- Handoffs are executed by calling `RunImpl.execute_handoffs()`. The method is patched with `patches._execute_handoffs()`
7989
"""
8090

8191
identifier = "openai_agents"
8292

8393
@staticmethod
8494
def setup_once() -> None:
8595
_patch_error_tracing()
86-
_patch_tools()
87-
_patch_model()
8896
_patch_runner()
97+
98+
library_version = parse_version(OPENAI_AGENTS_VERSION)
99+
if library_version is not None and library_version >= (
100+
0,
101+
8,
102+
):
103+
104+
@wraps(run_loop.get_all_tools)
105+
async def new_wrapped_get_all_tools(
106+
agent: "agents.Agent",
107+
context_wrapper: "agents.RunContextWrapper",
108+
) -> "list[agents.Tool]":
109+
return await _get_all_tools(
110+
run_loop.get_all_tools, agent, context_wrapper
111+
)
112+
113+
agents.run.get_all_tools = new_wrapped_get_all_tools
114+
115+
@wraps(turn_preparation.get_model)
116+
def new_wrapped_get_model(
117+
agent: "agents.Agent", run_config: "agents.RunConfig"
118+
) -> "agents.Model":
119+
return _get_model(turn_preparation.get_model, agent, run_config)
120+
121+
agents.run_internal.run_loop.get_model = new_wrapped_get_model
122+
123+
@wraps(run_loop.run_single_turn)
124+
async def new_wrapped_run_single_turn(
125+
*args: "Any", **kwargs: "Any"
126+
) -> "SingleStepResult":
127+
return await _run_single_turn(run_loop.run_single_turn, *args, **kwargs)
128+
129+
agents.run.run_single_turn = new_wrapped_run_single_turn
130+
131+
@wraps(run_loop.run_single_turn_streamed)
132+
async def new_wrapped_run_single_turn_streamed(
133+
*args: "Any", **kwargs: "Any"
134+
) -> "SingleStepResult":
135+
return await _run_single_turn_streamed(
136+
run_loop.run_single_turn_streamed, *args, **kwargs
137+
)
138+
139+
agents.run.run_single_turn_streamed = new_wrapped_run_single_turn_streamed
140+
141+
original_execute_handoffs = turn_resolution.execute_handoffs
142+
143+
@wraps(original_execute_handoffs)
144+
async def new_wrapped_execute_handoffs(
145+
*args: "Any", **kwargs: "Any"
146+
) -> "SingleStepResult":
147+
return await _execute_handoffs(
148+
original_execute_handoffs, *args, **kwargs
149+
)
150+
151+
agents.run_internal.turn_resolution.execute_handoffs = (
152+
new_wrapped_execute_handoffs
153+
)
154+
155+
original_execute_final_output = turn_resolution.execute_final_output
156+
157+
@wraps(turn_resolution.execute_final_output)
158+
async def new_wrapped_final_output(
159+
*args: "Any", **kwargs: "Any"
160+
) -> "SingleStepResult":
161+
return await _execute_final_output(
162+
original_execute_final_output, *args, **kwargs
163+
)
164+
165+
agents.run_internal.turn_resolution.execute_final_output = (
166+
new_wrapped_final_output
167+
)
168+
169+
return
170+
171+
original_get_all_tools = AgentRunner._get_all_tools
172+
173+
@wraps(AgentRunner._get_all_tools.__func__)
174+
async def old_wrapped_get_all_tools(
175+
cls: "agents.Runner",
176+
agent: "agents.Agent",
177+
context_wrapper: "agents.RunContextWrapper",
178+
) -> "list[agents.Tool]":
179+
return await _get_all_tools(original_get_all_tools, agent, context_wrapper)
180+
181+
agents.run.AgentRunner._get_all_tools = classmethod(old_wrapped_get_all_tools)
182+
183+
original_get_model = AgentRunner._get_model
184+
185+
@wraps(AgentRunner._get_model.__func__)
186+
def old_wrapped_get_model(
187+
cls: "agents.Runner", agent: "agents.Agent", run_config: "agents.RunConfig"
188+
) -> "agents.Model":
189+
return _get_model(original_get_model, agent, run_config)
190+
191+
agents.run.AgentRunner._get_model = classmethod(old_wrapped_get_model)
192+
193+
original_run_single_turn = AgentRunner._run_single_turn
194+
195+
@wraps(AgentRunner._run_single_turn.__func__)
196+
async def old_wrapped_run_single_turn(
197+
cls: "agents.Runner", *args: "Any", **kwargs: "Any"
198+
) -> "SingleStepResult":
199+
return await _run_single_turn(original_run_single_turn, *args, **kwargs)
200+
201+
agents.run.AgentRunner._run_single_turn = classmethod(
202+
old_wrapped_run_single_turn
203+
)
204+
205+
original_run_single_turn_streamed = AgentRunner._run_single_turn_streamed
206+
207+
@wraps(AgentRunner._run_single_turn_streamed.__func__)
208+
async def old_wrapped_run_single_turn_streamed(
209+
cls: "agents.Runner", *args: "Any", **kwargs: "Any"
210+
) -> "SingleStepResult":
211+
return await _run_single_turn_streamed(
212+
original_run_single_turn_streamed, *args, **kwargs
213+
)
214+
215+
agents.run.AgentRunner._run_single_turn_streamed = classmethod(
216+
old_wrapped_run_single_turn_streamed
217+
)
218+
219+
original_execute_handoffs = agents._run_impl.RunImpl.execute_handoffs
220+
221+
@wraps(agents._run_impl.RunImpl.execute_handoffs.__func__)
222+
async def old_wrapped_execute_handoffs(
223+
cls: "agents.Runner", *args: "Any", **kwargs: "Any"
224+
) -> "SingleStepResult":
225+
return await _execute_handoffs(original_execute_handoffs, *args, **kwargs)
226+
227+
agents._run_impl.RunImpl.execute_handoffs = classmethod(
228+
old_wrapped_execute_handoffs
229+
)
230+
231+
original_execute_final_output = agents._run_impl.RunImpl.execute_final_output
232+
233+
@wraps(agents._run_impl.RunImpl.execute_final_output.__func__)
234+
async def old_wrapped_final_output(
235+
cls: "agents.Runner", *args: "Any", **kwargs: "Any"
236+
) -> "SingleStepResult":
237+
return await _execute_final_output(
238+
original_execute_final_output, *args, **kwargs
239+
)
240+
241+
agents._run_impl.RunImpl.execute_final_output = classmethod(
242+
old_wrapped_final_output
243+
)
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
from .models import _create_get_model_wrapper # noqa: F401
2-
from .tools import _create_get_all_tools_wrapper # noqa: F401
1+
from .models import _get_model # noqa: F401
2+
from .tools import _get_all_tools # noqa: F401
33
from .runner import _create_run_wrapper, _create_run_streamed_wrapper # noqa: F401
4-
from .agent_run import _patch_agent_run # noqa: F401
4+
from .agent_run import (
5+
_run_single_turn,
6+
_run_single_turn_streamed,
7+
_execute_handoffs,
8+
_execute_final_output,
9+
) # noqa: F401
510
from .error_tracing import _patch_error_tracing # noqa: F401

0 commit comments

Comments
 (0)