Skip to content

Commit 94a92d8

Browse files
authored
Add input and output to invoke_agent span. (#4785)
Add the original input for the agent and the final output of the agent to the `invoke_agent` span. fixes #4512 fixes PY-1740
1 parent 9001126 commit 94a92d8

File tree

3 files changed

+68
-9
lines changed

3 files changed

+68
-9
lines changed

sentry_sdk/integrations/openai_agents/patches/agent_run.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ def _patch_agent_run():
2626
original_execute_handoffs = agents._run_impl.RunImpl.execute_handoffs
2727
original_execute_final_output = agents._run_impl.RunImpl.execute_final_output
2828

29-
def _start_invoke_agent_span(context_wrapper, agent):
30-
# type: (agents.RunContextWrapper, agents.Agent) -> None
29+
def _start_invoke_agent_span(context_wrapper, agent, kwargs):
30+
# type: (agents.RunContextWrapper, agents.Agent, dict[str, Any]) -> None
3131
"""Start an agent invocation span"""
3232
# Store the agent on the context wrapper so we can access it later
3333
context_wrapper._sentry_current_agent = agent
34-
invoke_agent_span(context_wrapper, agent)
34+
invoke_agent_span(context_wrapper, agent, kwargs)
3535

3636
def _end_invoke_agent_span(context_wrapper, agent, output=None):
3737
# type: (agents.RunContextWrapper, agents.Agent, Optional[Any]) -> None
@@ -72,7 +72,7 @@ async def patched_run_single_turn(cls, *args, **kwargs):
7272
if current_agent and current_agent != agent:
7373
_end_invoke_agent_span(context_wrapper, current_agent)
7474

75-
_start_invoke_agent_span(context_wrapper, agent)
75+
_start_invoke_agent_span(context_wrapper, agent, kwargs)
7676

7777
# Call original method with all the correct parameters
7878
result = await original_run_single_turn(*args, **kwargs)

sentry_sdk/integrations/openai_agents/spans/invoke_agent.py

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import sentry_sdk
2+
from sentry_sdk.ai.utils import set_data_normalized
23
from sentry_sdk.consts import OP, SPANDATA
4+
from sentry_sdk.scope import should_send_default_pii
5+
from sentry_sdk.utils import safe_serialize
36

47
from ..consts import SPAN_ORIGIN
58
from ..utils import _set_agent_data
@@ -11,8 +14,8 @@
1114
from typing import Any
1215

1316

14-
def invoke_agent_span(context, agent):
15-
# type: (agents.RunContextWrapper, agents.Agent) -> sentry_sdk.tracing.Span
17+
def invoke_agent_span(context, agent, kwargs):
18+
# type: (agents.RunContextWrapper, agents.Agent, dict[str, Any]) -> sentry_sdk.tracing.Span
1619
span = sentry_sdk.start_span(
1720
op=OP.GEN_AI_INVOKE_AGENT,
1821
name=f"invoke_agent {agent.name}",
@@ -22,13 +25,53 @@ def invoke_agent_span(context, agent):
2225

2326
span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent")
2427

28+
if should_send_default_pii():
29+
messages = []
30+
if agent.instructions:
31+
message = (
32+
agent.instructions
33+
if isinstance(agent.instructions, str)
34+
else safe_serialize(agent.instructions)
35+
)
36+
messages.append(
37+
{
38+
"content": [{"text": message, "type": "text"}],
39+
"role": "system",
40+
}
41+
)
42+
43+
original_input = kwargs.get("original_input")
44+
if original_input is not None:
45+
message = (
46+
original_input
47+
if isinstance(original_input, str)
48+
else safe_serialize(original_input)
49+
)
50+
messages.append(
51+
{
52+
"content": [{"text": message, "type": "text"}],
53+
"role": "user",
54+
}
55+
)
56+
57+
if len(messages) > 0:
58+
set_data_normalized(
59+
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages, unpack=False
60+
)
61+
2562
_set_agent_data(span, agent)
2663

2764
return span
2865

2966

3067
def update_invoke_agent_span(context, agent, output):
3168
# type: (agents.RunContextWrapper, agents.Agent, Any) -> None
32-
current_span = sentry_sdk.get_current_span()
33-
if current_span:
34-
current_span.__exit__(None, None, None)
69+
span = sentry_sdk.get_current_span()
70+
71+
if span:
72+
if should_send_default_pii():
73+
set_data_normalized(
74+
span, SPANDATA.GEN_AI_RESPONSE_TEXT, output, unpack=False
75+
)
76+
77+
span.__exit__(None, None, None)

tests/integrations/openai_agents/test_openai_agents.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ async def test_agent_invocation_span(
115115
sentry_init(
116116
integrations=[OpenAIAgentsIntegration()],
117117
traces_sample_rate=1.0,
118+
send_default_pii=True,
118119
)
119120

120121
events = capture_events()
@@ -134,6 +135,21 @@ async def test_agent_invocation_span(
134135
assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents"
135136

136137
assert invoke_agent_span["description"] == "invoke_agent test_agent"
138+
assert invoke_agent_span["data"]["gen_ai.request.messages"] == safe_serialize(
139+
[
140+
{
141+
"content": [
142+
{"text": "You are a helpful test assistant.", "type": "text"}
143+
],
144+
"role": "system",
145+
},
146+
{"content": [{"text": "Test input", "type": "text"}], "role": "user"},
147+
]
148+
)
149+
assert (
150+
invoke_agent_span["data"]["gen_ai.response.text"]
151+
== "Hello, how can I help you?"
152+
)
137153
assert invoke_agent_span["data"]["gen_ai.operation.name"] == "invoke_agent"
138154
assert invoke_agent_span["data"]["gen_ai.system"] == "openai"
139155
assert invoke_agent_span["data"]["gen_ai.agent.name"] == "test_agent"

0 commit comments

Comments
 (0)