From e9ab12d5bf83bade12ae11cedd1382308f07e356 Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Mon, 12 Oct 2026 15:13:44 +0200 Subject: [PATCH 1/2] chore: Deprecate gen_ai.responses with gen_ai.chat --- sentry_sdk/integrations/openai.py | 4 ++-- tests/integrations/openai/test_openai.py | 28 +++++++++++------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 90d602913c..805cd72675 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -1321,7 +1321,7 @@ def _new_sync_responses_create( span = sentry_sdk.start_span( name=f"responses {model}", attributes={ - "sentry.op": consts.OP.GEN_AI_RESPONSES, + "sentry.op": consts.OP.GEN_AI_CHAT, "sentry.origin": OpenAIIntegration.origin, SPANDATA.GEN_AI_PROVIDER_NAME: "openai", SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, @@ -1389,7 +1389,7 @@ async def _new_async_responses_create( span = sentry_sdk.start_span( name=f"responses {model}", attributes={ - "sentry.op": consts.OP.GEN_AI_RESPONSES, + "sentry.op": consts.OP.GEN_AI_CHAT, "sentry.origin": OpenAIIntegration.origin, SPANDATA.GEN_AI_PROVIDER_NAME: "openai", SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 21e7dd1739..30fcdc627e 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -2850,7 +2850,7 @@ def test_ai_client_span_responses_api_no_sensitive_data( "gen_ai.usage.output_tokens": 10, SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, - "sentry.op": "gen_ai.responses", + "sentry.op": OP.GEN_AI_CHAT, "sentry.origin": "auto.ai.openai", } @@ -3134,7 +3134,7 @@ def test_ai_client_span_responses_api( "gen_ai.request.messages": safe_serialize(expected_request_messages), "gen_ai.request.model": "gpt-4o", "gen_ai.response.text": "the model response", - "sentry.op": "gen_ai.responses", + "sentry.op": OP.GEN_AI_CHAT, "sentry.origin": "auto.ai.openai", } @@ -3265,7 +3265,7 @@ def test_error_in_responses_api( # make sure the span where the error occurred is captured sentry_sdk.flush() spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.op"] == "gen_ai.responses" + assert spans[0]["attributes"]["sentry.op"] == "gen_ai.chat" (error_event,) = (item.payload for item in items if item.type == "event") @@ -3476,7 +3476,7 @@ async def test_ai_client_span_responses_async_api( SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, "gen_ai.response.text": "the model response", - "sentry.op": "gen_ai.responses", + "sentry.op": OP.GEN_AI_CHAT, "sentry.origin": "auto.ai.openai", } @@ -3684,9 +3684,7 @@ async def test_ai_client_span_streaming_responses_async_api( sentry_sdk.flush() spans = [item.payload for item in items] spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_RESPONSES + span for span in spans if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT ] assert len(spans) == 1 @@ -3710,7 +3708,7 @@ async def test_ai_client_span_streaming_responses_async_api( "gen_ai.request.model": "gpt-4o", "gen_ai.response.text": "hello world", "sentry.environment": "production", - "sentry.op": "gen_ai.responses", + "sentry.op": OP.GEN_AI_CHAT, "sentry.origin": "auto.ai.openai", } @@ -3757,7 +3755,7 @@ async def test_error_in_responses_async_api( # make sure the span where the error occurred is captured sentry_sdk.flush() spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.op"] == "gen_ai.responses" + assert spans[0]["attributes"]["sentry.op"] == "gen_ai.chat" (error_event,) = (item.payload for item in items if item.type == "event") @@ -3892,7 +3890,7 @@ def test_streaming_responses_api( sentry_sdk.flush() (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" + assert span["attributes"]["sentry.op"] == "gen_ai.chat" assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 @@ -3960,7 +3958,7 @@ def test_streaming_responses_api_no_sensitive_data( sentry_sdk.flush() (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" + assert span["attributes"]["sentry.op"] == "gen_ai.chat" assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 @@ -4028,7 +4026,7 @@ async def test_streaming_responses_api_async( sentry_sdk.flush() (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" + assert span["attributes"]["sentry.op"] == "gen_ai.chat" assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 @@ -4096,7 +4094,7 @@ async def test_streaming_responses_api_async_no_sensitive_data( sentry_sdk.flush() (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" + assert span["attributes"]["sentry.op"] == "gen_ai.chat" assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 @@ -4441,7 +4439,7 @@ def test_streaming_responses_api_ttft( sentry_sdk.flush() span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" + assert span["attributes"]["sentry.op"] == "gen_ai.chat" # Verify TTFT is captured assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK in span["attributes"] @@ -4492,7 +4490,7 @@ async def test_streaming_responses_api_ttft_async( sentry_sdk.flush() span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" + assert span["attributes"]["sentry.op"] == "gen_ai.chat" # Verify TTFT is captured assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK in span["attributes"] From d8d670fb02d6913852bba10f5ad1fc45613bf67b Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Mon, 12 Oct 2026 19:35:03 +0200 Subject: [PATCH 2/2] migration guide and use op consts --- MIGRATION_GUIDE.md | 1 + tests/integrations/openai/test_openai.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index f753ae88d1..f43c3bf030 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -41,6 +41,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh Span ops are now a smaller, framework-neutral set. +- The OpenAI integration now emits `gen_ai.chat` instead of `gen_ai.responses`. - The Cohere integration now emits `gen_ai.chat` instead of `ai.chat_completions.create.cohere`, and `gen_ai.embeddings` instead of `ai.embeddings.create.cohere`. - The Django integration now emits `view.render` instead of `view.response.render`, `view` instead of `view.authenticate`, and `function` instead of `event.django`. - The Django, Starlette, Starlite, and Litestar integrations now emit `middleware` instead of `middleware.django`, `middleware.starlette`, `middleware.starlette.receive`, `middleware.starlette.send`, `middleware.starlite`, `middleware.starlite.receive`, `middleware.starlite.send`, `middleware.litestar`, `middleware.litestar.receive`, and `middleware.litestar.send`. diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 30fcdc627e..95d9e286cd 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -3265,7 +3265,7 @@ def test_error_in_responses_api( # make sure the span where the error occurred is captured sentry_sdk.flush() spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.op"] == "gen_ai.chat" + assert spans[0]["attributes"]["sentry.op"] == OP.GEN_AI_CHAT (error_event,) = (item.payload for item in items if item.type == "event") @@ -3755,7 +3755,7 @@ async def test_error_in_responses_async_api( # make sure the span where the error occurred is captured sentry_sdk.flush() spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.op"] == "gen_ai.chat" + assert spans[0]["attributes"]["sentry.op"] == OP.GEN_AI_CHAT (error_event,) = (item.payload for item in items if item.type == "event") @@ -3890,7 +3890,7 @@ def test_streaming_responses_api( sentry_sdk.flush() (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 @@ -3958,7 +3958,7 @@ def test_streaming_responses_api_no_sensitive_data( sentry_sdk.flush() (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 @@ -4026,7 +4026,7 @@ async def test_streaming_responses_api_async( sentry_sdk.flush() (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 @@ -4094,7 +4094,7 @@ async def test_streaming_responses_api_async_no_sensitive_data( sentry_sdk.flush() (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 @@ -4439,7 +4439,7 @@ def test_streaming_responses_api_ttft( sentry_sdk.flush() span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT # Verify TTFT is captured assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK in span["attributes"] @@ -4490,7 +4490,7 @@ async def test_streaming_responses_api_ttft_async( sentry_sdk.flush() span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT # Verify TTFT is captured assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK in span["attributes"]