diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 480db9132d..45aac3d410 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -347,6 +347,16 @@ def _set_responses_api_input_data( if top_p is not None and _is_given(top_p): span.set_data(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) + conversation = kwargs.get("conversation") + if conversation is not None and _is_given(conversation): + conversation_id: "Optional[str]" = None + if isinstance(conversation, str): + conversation_id = conversation + elif isinstance(conversation, dict): + conversation_id = conversation.get("id") + if conversation_id is not None: + span.set_data(SPANDATA.GEN_AI_CONVERSATION_ID, conversation_id) + if not should_send_default_pii() or not integration.include_prompts: set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") return diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 20bbf2adf5..677beb5681 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -2836,6 +2836,44 @@ def test_ai_client_span_responses_api( assert spans[0]["data"] == expected_data +@pytest.mark.parametrize( + "conversation, expected_id", + [ + pytest.param(omit, None, id="omit"), + pytest.param(None, None, id="none"), + pytest.param("conv_abc123", "conv_abc123", id="string"), + pytest.param({"id": "conv_abc123"}, "conv_abc123", id="dict"), + ], +) +@pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") +def test_responses_api_conversation_id( + sentry_init, capture_events, conversation, expected_id +): + sentry_init( + integrations=[OpenAIIntegration()], + traces_sample_rate=1.0, + ) + events = capture_events() + + client = OpenAI(api_key="z") + client.responses._post = mock.Mock(return_value=EXAMPLE_RESPONSE) + + with start_transaction(name="openai tx"): + client.responses.create( + model="gpt-4o", + input="hello", + conversation=conversation, + ) + + (transaction,) = events + (span,) = transaction["spans"] + + if expected_id is None: + assert "gen_ai.conversation.id" not in span["data"] + else: + assert span["data"]["gen_ai.conversation.id"] == expected_id + + @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_error_in_responses_api(sentry_init, capture_events): sentry_init(