@@ -2857,3 +2857,194 @@ def mock_get_model(agent, run_config):
28572857
28582858 # Verify streaming flag is set
28592859 assert chat_span ._data .get (SPANDATA .GEN_AI_RESPONSE_STREAMING ) is True
2860+
2861+
2862+ @pytest .mark .skipif (
2863+ parse_version (OPENAI_AGENTS_VERSION ) < (0 , 4 , 0 ),
2864+ reason = "conversation_id support requires openai-agents >= 0.4.0" ,
2865+ )
2866+ @pytest .mark .asyncio
2867+ async def test_conversation_id_on_all_spans (
2868+ sentry_init , capture_events , test_agent , mock_model_response
2869+ ):
2870+ """
2871+ Test that gen_ai.conversation.id is set on all AI-related spans when passed to Runner.run().
2872+ """
2873+
2874+ with patch .dict (os .environ , {"OPENAI_API_KEY" : "test-key" }):
2875+ with patch (
2876+ "agents.models.openai_responses.OpenAIResponsesModel.get_response"
2877+ ) as mock_get_response :
2878+ mock_get_response .return_value = mock_model_response
2879+
2880+ sentry_init (
2881+ integrations = [OpenAIAgentsIntegration ()],
2882+ traces_sample_rate = 1.0 ,
2883+ )
2884+
2885+ events = capture_events ()
2886+
2887+ result = await agents .Runner .run (
2888+ test_agent ,
2889+ "Test input" ,
2890+ run_config = test_run_config ,
2891+ conversation_id = "conv_test_123" ,
2892+ )
2893+
2894+ assert result is not None
2895+
2896+ (transaction ,) = events
2897+ spans = transaction ["spans" ]
2898+ invoke_agent_span , ai_client_span = spans
2899+
2900+ # Verify workflow span (transaction) has conversation_id
2901+ assert (
2902+ transaction ["contexts" ]["trace" ]["data" ]["gen_ai.conversation.id" ]
2903+ == "conv_test_123"
2904+ )
2905+
2906+ # Verify invoke_agent span has conversation_id
2907+ assert invoke_agent_span ["data" ]["gen_ai.conversation.id" ] == "conv_test_123"
2908+
2909+ # Verify ai_client span has conversation_id
2910+ assert ai_client_span ["data" ]["gen_ai.conversation.id" ] == "conv_test_123"
2911+
2912+
2913+ @pytest .mark .skipif (
2914+ parse_version (OPENAI_AGENTS_VERSION ) < (0 , 4 , 0 ),
2915+ reason = "conversation_id support requires openai-agents >= 0.4.0" ,
2916+ )
2917+ @pytest .mark .asyncio
2918+ async def test_conversation_id_on_tool_span (sentry_init , capture_events , test_agent ):
2919+ """
2920+ Test that gen_ai.conversation.id is set on tool execution spans when passed to Runner.run().
2921+ """
2922+
2923+ @agents .function_tool
2924+ def simple_tool (message : str ) -> str :
2925+ """A simple tool"""
2926+ return f"Result: { message } "
2927+
2928+ agent_with_tool = test_agent .clone (tools = [simple_tool ])
2929+
2930+ with patch .dict (os .environ , {"OPENAI_API_KEY" : "test-key" }):
2931+ with patch (
2932+ "agents.models.openai_responses.OpenAIResponsesModel.get_response"
2933+ ) as mock_get_response :
2934+ tool_call = ResponseFunctionToolCall (
2935+ id = "call_123" ,
2936+ call_id = "call_123" ,
2937+ name = "simple_tool" ,
2938+ type = "function_call" ,
2939+ arguments = '{"message": "hello"}' ,
2940+ )
2941+
2942+ tool_response = ModelResponse (
2943+ output = [tool_call ],
2944+ usage = Usage (
2945+ requests = 1 , input_tokens = 10 , output_tokens = 5 , total_tokens = 15
2946+ ),
2947+ response_id = "resp_tool_456" ,
2948+ )
2949+
2950+ final_response = ModelResponse (
2951+ output = [
2952+ ResponseOutputMessage (
2953+ id = "msg_final" ,
2954+ type = "message" ,
2955+ status = "completed" ,
2956+ content = [
2957+ ResponseOutputText (
2958+ text = "Done" ,
2959+ type = "output_text" ,
2960+ annotations = [],
2961+ )
2962+ ],
2963+ role = "assistant" ,
2964+ )
2965+ ],
2966+ usage = Usage (
2967+ requests = 1 , input_tokens = 15 , output_tokens = 10 , total_tokens = 25
2968+ ),
2969+ response_id = "resp_final_789" ,
2970+ )
2971+
2972+ mock_get_response .side_effect = [tool_response , final_response ]
2973+
2974+ sentry_init (
2975+ integrations = [OpenAIAgentsIntegration ()],
2976+ traces_sample_rate = 1.0 ,
2977+ )
2978+
2979+ events = capture_events ()
2980+
2981+ await agents .Runner .run (
2982+ agent_with_tool ,
2983+ "Use the tool" ,
2984+ run_config = test_run_config ,
2985+ conversation_id = "conv_tool_test_456" ,
2986+ )
2987+
2988+ (transaction ,) = events
2989+ spans = transaction ["spans" ]
2990+
2991+ # Find the tool span
2992+ tool_span = None
2993+ for span in spans :
2994+ if span .get ("description" , "" ).startswith ("execute_tool" ):
2995+ tool_span = span
2996+ break
2997+
2998+ assert tool_span is not None
2999+ # Tool span should have the conversation_id passed to Runner.run()
3000+ assert tool_span ["data" ]["gen_ai.conversation.id" ] == "conv_tool_test_456"
3001+
3002+ # Workflow span (transaction) should have the same conversation_id
3003+ assert (
3004+ transaction ["contexts" ]["trace" ]["data" ]["gen_ai.conversation.id" ]
3005+ == "conv_tool_test_456"
3006+ )
3007+
3008+
3009+ @pytest .mark .skipif (
3010+ parse_version (OPENAI_AGENTS_VERSION ) < (0 , 4 , 0 ),
3011+ reason = "conversation_id support requires openai-agents >= 0.4.0" ,
3012+ )
3013+ @pytest .mark .asyncio
3014+ async def test_no_conversation_id_when_not_provided (
3015+ sentry_init , capture_events , test_agent , mock_model_response
3016+ ):
3017+ """
3018+ Test that gen_ai.conversation.id is not set when not passed to Runner.run().
3019+ """
3020+
3021+ with patch .dict (os .environ , {"OPENAI_API_KEY" : "test-key" }):
3022+ with patch (
3023+ "agents.models.openai_responses.OpenAIResponsesModel.get_response"
3024+ ) as mock_get_response :
3025+ mock_get_response .return_value = mock_model_response
3026+
3027+ sentry_init (
3028+ integrations = [OpenAIAgentsIntegration ()],
3029+ traces_sample_rate = 1.0 ,
3030+ )
3031+
3032+ events = capture_events ()
3033+
3034+ # Don't pass conversation_id
3035+ result = await agents .Runner .run (
3036+ test_agent , "Test input" , run_config = test_run_config
3037+ )
3038+
3039+ assert result is not None
3040+
3041+ (transaction ,) = events
3042+ spans = transaction ["spans" ]
3043+ invoke_agent_span , ai_client_span = spans
3044+
3045+ # Verify conversation_id is NOT set on any spans
3046+ assert "gen_ai.conversation.id" not in transaction ["contexts" ]["trace" ].get (
3047+ "data" , {}
3048+ )
3049+ assert "gen_ai.conversation.id" not in invoke_agent_span .get ("data" , {})
3050+ assert "gen_ai.conversation.id" not in ai_client_span .get ("data" , {})
0 commit comments