Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions sentry_sdk/integrations/openai_agents/patches/agent_run.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
from functools import wraps

from sentry_sdk.integrations import DidNotEnable

from ..spans import invoke_agent_span, update_invoke_agent_span, handoff_span

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Any, Optional


try:
import agents
except ImportError:
Expand Down Expand Up @@ -62,7 +60,6 @@ def _get_current_agent(context_wrapper):
async def patched_run_single_turn(cls, *args, **kwargs):
# type: (agents.Runner, *Any, **Any) -> Any
"""Patched _run_single_turn that creates agent invocation spans"""

agent = kwargs.get("agent")
context_wrapper = kwargs.get("context_wrapper")
should_run_agent_start_hooks = kwargs.get("should_run_agent_start_hooks")
Expand Down
33 changes: 18 additions & 15 deletions sentry_sdk/integrations/openai_agents/patches/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,23 @@ def _create_run_wrapper(original_func):
@wraps(original_func)
async def wrapper(*args, **kwargs):
# type: (*Any, **Any) -> Any
agent = args[0]
with agent_workflow_span(agent):
result = None
try:
result = await original_func(*args, **kwargs)
return result
except Exception as exc:
_capture_exception(exc)

# It could be that there is a "invoke agent" span still open
current_span = sentry_sdk.get_current_span()
if current_span is not None and current_span.timestamp is None:
current_span.__exit__(None, None, None)

raise exc from None
# Isolate each workflow so that when agents are run in asyncio tasks they
# don't touch each other's scopes
with sentry_sdk.isolation_scope():
agent = args[0]
with agent_workflow_span(agent):
result = None
try:
result = await original_func(*args, **kwargs)
return result
except Exception as exc:
_capture_exception(exc)

# It could be that there is a "invoke agent" span still open
current_span = sentry_sdk.get_current_span()
if current_span is not None and current_span.timestamp is None:
current_span.__exit__(None, None, None)

raise exc from None

return wrapper
43 changes: 43 additions & 0 deletions tests/integrations/openai_agents/test_openai_agents.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
import re
import pytest
from unittest.mock import MagicMock, patch
Expand Down Expand Up @@ -637,3 +638,45 @@ async def test_error_handling(sentry_init, capture_events, test_agent):
assert ai_client_span["description"] == "chat gpt-4"
assert ai_client_span["origin"] == "auto.ai.openai_agents"
assert ai_client_span["tags"]["status"] == "internal_error"


@pytest.mark.asyncio
async def test_multiple_agents_asyncio(
sentry_init, capture_events, test_agent, mock_model_response
):
"""
Test that multiple agents can be run at the same time in asyncio tasks
without interfering with each other.
"""

with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}):
with patch(
"agents.models.openai_responses.OpenAIResponsesModel.get_response"
) as mock_get_response:
mock_get_response.return_value = mock_model_response

sentry_init(
integrations=[OpenAIAgentsIntegration()],
traces_sample_rate=1.0,
)

events = capture_events()

async def run():
await agents.Runner.run(
starting_agent=test_agent,
input="Test input",
run_config=test_run_config,
)

await asyncio.gather(*[run() for _ in range(3)])

assert len(events) == 3
txn1, txn2, txn3 = events

assert txn1["type"] == "transaction"
assert txn1["transaction"] == "test_agent workflow"
assert txn2["type"] == "transaction"
assert txn2["transaction"] == "test_agent workflow"
assert txn3["type"] == "transaction"
assert txn3["transaction"] == "test_agent workflow"