From 2df4dc7589da9c9f6a253fb07e02c2a757ec63c2 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Thu, 8 May 2025 12:57:06 +0200
Subject: [PATCH 1/3] Pin snowballstemmer for now (#4372)

Make apidocs buildable again
---
 requirements-docs.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/requirements-docs.txt b/requirements-docs.txt
index 81e04ba3ef..a662a0d83f 100644
--- a/requirements-docs.txt
+++ b/requirements-docs.txt
@@ -3,3 +3,4 @@ shibuya
 sphinx<8.2
 sphinx-autodoc-typehints[type_comments]>=1.8.0
 typing-extensions
+snowballstemmer<3.0

From ca5ba8957101e5b1b8ac76d1c94a99e5db95bd9c Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Thu, 8 May 2025 13:14:14 +0200
Subject: [PATCH 2/3] Fix Discord link (#4371)

---
 README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 10bc8eb2ed..a3afdc6e72 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
 _Bad software is everywhere, and we're tired of it. Sentry is on a mission to help developers write better software faster, so we can get back to enjoying technology. If you want to join us
 [<kbd>**Check out our open positions**</kbd>](https://sentry.io/careers/)_.
 
-[![Discord](https://img.shields.io/discord/621778831602221064?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
+[![Discord](https://img.shields.io/discord/621778831602221064?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.com/invite/Ww9hbqr)
 [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=@getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry)
 [![PyPi page link -- version](https://img.shields.io/pypi/v/sentry-sdk.svg)](https://pypi.python.org/pypi/sentry-sdk)
 <img src="https://img.shields.io/badge/python-3.7 | 3.8 | 3.9 | 3.10 | 3.11 | 3.12 | 3.13-blue.svg" alt="python">
@@ -106,7 +106,7 @@ If you encounter issues or need help setting up or configuring the SDK, don't he
 Here are all resources to help you make the most of Sentry:
 
 - [Documentation](https://docs.sentry.io/platforms/python/) - Official documentation to get started.
-- [Discord](https://img.shields.io/discord/621778831602221064) - Join our Discord community.
+- [Discord](https://discord.com/invite/Ww9hbqr) - Join our Discord community.
 - [X/Twitter](https://twitter.com/intent/follow?screen_name=getsentry) -  Follow us on X (Twitter) for updates.
 - [Stack Overflow](https://stackoverflow.com/questions/tagged/sentry) - Questions and answers related to Sentry.
 

From cb824834e40921e9d488f81afc18495d811883a8 Mon Sep 17 00:00:00 2001
From: Anton Pirker <anton.pirker@sentry.io>
Date: Fri, 9 May 2025 10:34:09 +0200
Subject: [PATCH 3/3] Make use of `SPANDATA` consistent (#4373)

The AI integrations sometimes used plain strings for setting `SPANDATA`
attributes. Changed to always use `SPANDATA`.
---
 sentry_sdk/ai/monitoring.py                   |  7 ++-
 sentry_sdk/consts.py                          | 63 ++++++++++++++++++-
 sentry_sdk/integrations/cohere.py             | 20 +++---
 sentry_sdk/integrations/huggingface_hub.py    |  4 +-
 sentry_sdk/integrations/openai.py             |  8 +--
 .../integrations/anthropic/test_anthropic.py  | 14 ++---
 tests/integrations/cohere/test_cohere.py      | 29 ++++-----
 .../huggingface_hub/test_huggingface_hub.py   | 17 ++---
 .../integrations/langchain/test_langchain.py  | 26 ++++----
 tests/integrations/openai/test_openai.py      | 41 ++++++------
 10 files changed, 147 insertions(+), 82 deletions(-)

diff --git a/sentry_sdk/ai/monitoring.py b/sentry_sdk/ai/monitoring.py
index 860833b8f5..ed33acd0f1 100644
--- a/sentry_sdk/ai/monitoring.py
+++ b/sentry_sdk/ai/monitoring.py
@@ -1,6 +1,7 @@
 import inspect
 from functools import wraps
 
+from sentry_sdk.consts import SPANDATA
 import sentry_sdk.utils
 from sentry_sdk import start_span
 from sentry_sdk.tracing import Span
@@ -39,7 +40,7 @@ def sync_wrapped(*args, **kwargs):
                 for k, v in kwargs.pop("sentry_data", {}).items():
                     span.set_data(k, v)
                 if curr_pipeline:
-                    span.set_data("ai.pipeline.name", curr_pipeline)
+                    span.set_data(SPANDATA.AI_PIPELINE_NAME, curr_pipeline)
                     return f(*args, **kwargs)
                 else:
                     _ai_pipeline_name.set(description)
@@ -68,7 +69,7 @@ async def async_wrapped(*args, **kwargs):
                 for k, v in kwargs.pop("sentry_data", {}).items():
                     span.set_data(k, v)
                 if curr_pipeline:
-                    span.set_data("ai.pipeline.name", curr_pipeline)
+                    span.set_data(SPANDATA.AI_PIPELINE_NAME, curr_pipeline)
                     return await f(*args, **kwargs)
                 else:
                     _ai_pipeline_name.set(description)
@@ -100,7 +101,7 @@ def record_token_usage(
     # type: (Span, Optional[int], Optional[int], Optional[int]) -> None
     ai_pipeline_name = get_ai_pipeline_name()
     if ai_pipeline_name:
-        span.set_data("ai.pipeline.name", ai_pipeline_name)
+        span.set_data(SPANDATA.AI_PIPELINE_NAME, ai_pipeline_name)
     if prompt_tokens is not None:
         span.set_measurement("ai_prompt_tokens_used", value=prompt_tokens)
     if completion_tokens is not None:
diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py
index e1f18fe4ae..e3c29fc2d4 100644
--- a/sentry_sdk/consts.py
+++ b/sentry_sdk/consts.py
@@ -187,7 +187,7 @@ class SPANDATA:
     For an AI model call, the format of the response
     """
 
-    AI_LOGIT_BIAS = "ai.response_format"
+    AI_LOGIT_BIAS = "ai.logit_bias"
     """
     For an AI model call, the logit bias
     """
@@ -204,7 +204,6 @@ class SPANDATA:
     Minimize pre-processing done to the prompt sent to the LLM.
     Example: true
     """
-
     AI_RESPONSES = "ai.responses"
     """
     The responses to an AI model call. Always as a list.
@@ -217,6 +216,66 @@ class SPANDATA:
     Example: 123.45
     """
 
+    AI_CITATIONS = "ai.citations"
+    """
+    References or sources cited by the AI model in its response.
+    Example: ["Smith et al. 2020", "Jones 2019"]
+    """
+
+    AI_DOCUMENTS = "ai.documents"
+    """
+    Documents or content chunks used as context for the AI model.
+    Example: ["doc1.txt", "doc2.pdf"]
+    """
+
+    AI_SEARCH_QUERIES = "ai.search_queries"
+    """
+    Queries used to search for relevant context or documents.
+    Example: ["climate change effects", "renewable energy"]
+    """
+
+    AI_SEARCH_RESULTS = "ai.search_results"
+    """
+    Results returned from search queries for context.
+    Example: ["Result 1", "Result 2"]
+    """
+
+    AI_GENERATION_ID = "ai.generation_id"
+    """
+    Unique identifier for the completion.
+    Example: "gen_123abc"
+    """
+
+    AI_SEARCH_REQUIRED = "ai.is_search_required"
+    """
+    Boolean indicating if the model needs to perform a search.
+    Example: true
+    """
+
+    AI_FINISH_REASON = "ai.finish_reason"
+    """
+    The reason why the model stopped generating.
+    Example: "length"
+    """
+
+    AI_PIPELINE_NAME = "ai.pipeline.name"
+    """
+    Name of the AI pipeline or chain being executed.
+    Example: "qa-pipeline"
+    """
+
+    AI_TEXTS = "ai.texts"
+    """
+    Raw text inputs provided to the model.
+    Example: ["What is machine learning?"]
+    """
+
+    AI_WARNINGS = "ai.warnings"
+    """
+    Warning messages generated during model execution.
+    Example: ["Token limit exceeded"]
+    """
+
     DB_NAME = "db.name"
     """
     The name of the database being accessed. For commands that switch the database, this should be set to the target database (even if the command fails).
diff --git a/sentry_sdk/integrations/cohere.py b/sentry_sdk/integrations/cohere.py
index b4c2af91da..433b285bf0 100644
--- a/sentry_sdk/integrations/cohere.py
+++ b/sentry_sdk/integrations/cohere.py
@@ -52,17 +52,17 @@
 }
 
 COLLECTED_CHAT_RESP_ATTRS = {
-    "generation_id": "ai.generation_id",
-    "is_search_required": "ai.is_search_required",
-    "finish_reason": "ai.finish_reason",
+    "generation_id": SPANDATA.AI_GENERATION_ID,
+    "is_search_required": SPANDATA.AI_SEARCH_REQUIRED,
+    "finish_reason": SPANDATA.AI_FINISH_REASON,
 }
 
 COLLECTED_PII_CHAT_RESP_ATTRS = {
-    "citations": "ai.citations",
-    "documents": "ai.documents",
-    "search_queries": "ai.search_queries",
-    "search_results": "ai.search_results",
-    "tool_calls": "ai.tool_calls",
+    "citations": SPANDATA.AI_CITATIONS,
+    "documents": SPANDATA.AI_DOCUMENTS,
+    "search_queries": SPANDATA.AI_SEARCH_QUERIES,
+    "search_results": SPANDATA.AI_SEARCH_RESULTS,
+    "tool_calls": SPANDATA.AI_TOOL_CALLS,
 }
 
 
@@ -127,7 +127,7 @@ def collect_chat_response_fields(span, res, include_pii):
                 )
 
             if hasattr(res.meta, "warnings"):
-                set_data_normalized(span, "ai.warnings", res.meta.warnings)
+                set_data_normalized(span, SPANDATA.AI_WARNINGS, res.meta.warnings)
 
     @wraps(f)
     def new_chat(*args, **kwargs):
@@ -238,7 +238,7 @@ def new_embed(*args, **kwargs):
                 should_send_default_pii() and integration.include_prompts
             ):
                 if isinstance(kwargs["texts"], str):
-                    set_data_normalized(span, "ai.texts", [kwargs["texts"]])
+                    set_data_normalized(span, SPANDATA.AI_TEXTS, [kwargs["texts"]])
                 elif (
                     isinstance(kwargs["texts"], list)
                     and len(kwargs["texts"]) > 0
diff --git a/sentry_sdk/integrations/huggingface_hub.py b/sentry_sdk/integrations/huggingface_hub.py
index d09f6e2163..dfac77e996 100644
--- a/sentry_sdk/integrations/huggingface_hub.py
+++ b/sentry_sdk/integrations/huggingface_hub.py
@@ -97,7 +97,7 @@ def new_text_generation(*args, **kwargs):
                 if should_send_default_pii() and integration.include_prompts:
                     set_data_normalized(
                         span,
-                        "ai.responses",
+                        SPANDATA.AI_RESPONSES,
                         [res],
                     )
                 span.__exit__(None, None, None)
@@ -107,7 +107,7 @@ def new_text_generation(*args, **kwargs):
                 if should_send_default_pii() and integration.include_prompts:
                     set_data_normalized(
                         span,
-                        "ai.responses",
+                        SPANDATA.AI_RESPONSES,
                         [res.generated_text],
                     )
                 if res.details is not None and res.details.generated_tokens > 0:
diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py
index 61d335b170..e95753f6e1 100644
--- a/sentry_sdk/integrations/openai.py
+++ b/sentry_sdk/integrations/openai.py
@@ -155,7 +155,7 @@ def _new_chat_completion_common(f, *args, **kwargs):
             if should_send_default_pii() and integration.include_prompts:
                 set_data_normalized(
                     span,
-                    "ai.responses",
+                    SPANDATA.AI_RESPONSES,
                     list(map(lambda x: x.message, res.choices)),
                 )
             _calculate_chat_completion_usage(
@@ -329,15 +329,15 @@ def _new_embeddings_create_common(f, *args, **kwargs):
             should_send_default_pii() and integration.include_prompts
         ):
             if isinstance(kwargs["input"], str):
-                set_data_normalized(span, "ai.input_messages", [kwargs["input"]])
+                set_data_normalized(span, SPANDATA.AI_INPUT_MESSAGES, [kwargs["input"]])
             elif (
                 isinstance(kwargs["input"], list)
                 and len(kwargs["input"]) > 0
                 and isinstance(kwargs["input"][0], str)
             ):
-                set_data_normalized(span, "ai.input_messages", kwargs["input"])
+                set_data_normalized(span, SPANDATA.AI_INPUT_MESSAGES, kwargs["input"])
         if "model" in kwargs:
-            set_data_normalized(span, "ai.model_id", kwargs["model"])
+            set_data_normalized(span, SPANDATA.AI_MODEL_ID, kwargs["model"])
 
         response = yield f, args, kwargs
 
diff --git a/tests/integrations/anthropic/test_anthropic.py b/tests/integrations/anthropic/test_anthropic.py
index 7f6622a1ba..9ab0f879d1 100644
--- a/tests/integrations/anthropic/test_anthropic.py
+++ b/tests/integrations/anthropic/test_anthropic.py
@@ -128,7 +128,7 @@ def test_nonstreaming_create_message(
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 10
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 20
     assert span["measurements"]["ai_total_tokens_used"]["value"] == 30
-    assert span["data"]["ai.streaming"] is False
+    assert span["data"][SPANDATA.AI_STREAMING] is False
 
 
 @pytest.mark.asyncio
@@ -196,7 +196,7 @@ async def test_nonstreaming_create_message_async(
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 10
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 20
     assert span["measurements"]["ai_total_tokens_used"]["value"] == 30
-    assert span["data"]["ai.streaming"] is False
+    assert span["data"][SPANDATA.AI_STREAMING] is False
 
 
 @pytest.mark.parametrize(
@@ -296,7 +296,7 @@ def test_streaming_create_message(
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 10
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 30
     assert span["measurements"]["ai_total_tokens_used"]["value"] == 40
-    assert span["data"]["ai.streaming"] is True
+    assert span["data"][SPANDATA.AI_STREAMING] is True
 
 
 @pytest.mark.asyncio
@@ -399,7 +399,7 @@ async def test_streaming_create_message_async(
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 10
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 30
     assert span["measurements"]["ai_total_tokens_used"]["value"] == 40
-    assert span["data"]["ai.streaming"] is True
+    assert span["data"][SPANDATA.AI_STREAMING] is True
 
 
 @pytest.mark.skipif(
@@ -528,7 +528,7 @@ def test_streaming_create_message_with_input_json_delta(
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 366
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 51
     assert span["measurements"]["ai_total_tokens_used"]["value"] == 417
-    assert span["data"]["ai.streaming"] is True
+    assert span["data"][SPANDATA.AI_STREAMING] is True
 
 
 @pytest.mark.asyncio
@@ -665,7 +665,7 @@ async def test_streaming_create_message_with_input_json_delta_async(
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 366
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 51
     assert span["measurements"]["ai_total_tokens_used"]["value"] == 417
-    assert span["data"]["ai.streaming"] is True
+    assert span["data"][SPANDATA.AI_STREAMING] is True
 
 
 def test_exception_message_create(sentry_init, capture_events):
@@ -810,7 +810,7 @@ def test_add_ai_data_to_span_with_input_json_delta(sentry_init):
         assert span._data.get(SPANDATA.AI_RESPONSES) == [
             {"type": "text", "text": "{'test': 'data','more': 'json'}"}
         ]
-        assert span._data.get("ai.streaming") is True
+        assert span._data.get(SPANDATA.AI_STREAMING) is True
         assert span._measurements.get("ai_prompt_tokens_used")["value"] == 10
         assert span._measurements.get("ai_completion_tokens_used")["value"] == 20
         assert span._measurements.get("ai_total_tokens_used")["value"] == 30
diff --git a/tests/integrations/cohere/test_cohere.py b/tests/integrations/cohere/test_cohere.py
index c0dff2214e..6c1185a28e 100644
--- a/tests/integrations/cohere/test_cohere.py
+++ b/tests/integrations/cohere/test_cohere.py
@@ -5,6 +5,7 @@
 from cohere import Client, ChatMessage
 
 from sentry_sdk import start_transaction
+from sentry_sdk.consts import SPANDATA
 from sentry_sdk.integrations.cohere import CohereIntegration
 
 from unittest import mock  # python 3.3 and above
@@ -53,15 +54,15 @@ def test_nonstreaming_chat(
     assert tx["type"] == "transaction"
     span = tx["spans"][0]
     assert span["op"] == "ai.chat_completions.create.cohere"
-    assert span["data"]["ai.model_id"] == "some-model"
+    assert span["data"][SPANDATA.AI_MODEL_ID] == "some-model"
 
     if send_default_pii and include_prompts:
-        assert "some context" in span["data"]["ai.input_messages"][0]["content"]
-        assert "hello" in span["data"]["ai.input_messages"][1]["content"]
-        assert "the model response" in span["data"]["ai.responses"]
+        assert "some context" in span["data"][SPANDATA.AI_INPUT_MESSAGES][0]["content"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES][1]["content"]
+        assert "the model response" in span["data"][SPANDATA.AI_RESPONSES]
     else:
-        assert "ai.input_messages" not in span["data"]
-        assert "ai.responses" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
+        assert SPANDATA.AI_RESPONSES not in span["data"]
 
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 10
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 20
@@ -124,15 +125,15 @@ def test_streaming_chat(sentry_init, capture_events, send_default_pii, include_p
     assert tx["type"] == "transaction"
     span = tx["spans"][0]
     assert span["op"] == "ai.chat_completions.create.cohere"
-    assert span["data"]["ai.model_id"] == "some-model"
+    assert span["data"][SPANDATA.AI_MODEL_ID] == "some-model"
 
     if send_default_pii and include_prompts:
-        assert "some context" in span["data"]["ai.input_messages"][0]["content"]
-        assert "hello" in span["data"]["ai.input_messages"][1]["content"]
-        assert "the model response" in span["data"]["ai.responses"]
+        assert "some context" in span["data"][SPANDATA.AI_INPUT_MESSAGES][0]["content"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES][1]["content"]
+        assert "the model response" in span["data"][SPANDATA.AI_RESPONSES]
     else:
-        assert "ai.input_messages" not in span["data"]
-        assert "ai.responses" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
+        assert SPANDATA.AI_RESPONSES not in span["data"]
 
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 10
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 20
@@ -194,9 +195,9 @@ def test_embed(sentry_init, capture_events, send_default_pii, include_prompts):
     span = tx["spans"][0]
     assert span["op"] == "ai.embeddings.create.cohere"
     if send_default_pii and include_prompts:
-        assert "hello" in span["data"]["ai.input_messages"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES]
     else:
-        assert "ai.input_messages" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
 
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 10
     assert span["measurements"]["ai_total_tokens_used"]["value"] == 10
diff --git a/tests/integrations/huggingface_hub/test_huggingface_hub.py b/tests/integrations/huggingface_hub/test_huggingface_hub.py
index 090b0e4f3e..ee47cc7e56 100644
--- a/tests/integrations/huggingface_hub/test_huggingface_hub.py
+++ b/tests/integrations/huggingface_hub/test_huggingface_hub.py
@@ -8,6 +8,7 @@
 from huggingface_hub.errors import OverloadedError
 
 from sentry_sdk import start_transaction
+from sentry_sdk.consts import SPANDATA
 from sentry_sdk.integrations.huggingface_hub import HuggingfaceHubIntegration
 
 
@@ -67,11 +68,11 @@ def test_nonstreaming_chat_completion(
     assert span["op"] == "ai.chat_completions.create.huggingface_hub"
 
     if send_default_pii and include_prompts:
-        assert "hello" in span["data"]["ai.input_messages"]
-        assert "the model response" in span["data"]["ai.responses"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES]
+        assert "the model response" in span["data"][SPANDATA.AI_RESPONSES]
     else:
-        assert "ai.input_messages" not in span["data"]
-        assert "ai.responses" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
+        assert SPANDATA.AI_RESPONSES not in span["data"]
 
     if details_arg:
         assert span["measurements"]["ai_total_tokens_used"]["value"] == 10
@@ -126,11 +127,11 @@ def test_streaming_chat_completion(
     assert span["op"] == "ai.chat_completions.create.huggingface_hub"
 
     if send_default_pii and include_prompts:
-        assert "hello" in span["data"]["ai.input_messages"]
-        assert "the model response" in span["data"]["ai.responses"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES]
+        assert "the model response" in span["data"][SPANDATA.AI_RESPONSES]
     else:
-        assert "ai.input_messages" not in span["data"]
-        assert "ai.responses" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
+        assert SPANDATA.AI_RESPONSES not in span["data"]
 
     if details_arg:
         assert span["measurements"]["ai_total_tokens_used"]["value"] == 10
diff --git a/tests/integrations/langchain/test_langchain.py b/tests/integrations/langchain/test_langchain.py
index b9e5705b88..3f1b3b1da5 100644
--- a/tests/integrations/langchain/test_langchain.py
+++ b/tests/integrations/langchain/test_langchain.py
@@ -3,6 +3,8 @@
 
 import pytest
 
+from sentry_sdk.consts import SPANDATA
+
 try:
     # Langchain >= 0.2
     from langchain_openai import ChatOpenAI
@@ -189,23 +191,23 @@ def test_langchain_agent(
     if send_default_pii and include_prompts:
         assert (
             "You are very powerful"
-            in chat_spans[0]["data"]["ai.input_messages"][0]["content"]
+            in chat_spans[0]["data"][SPANDATA.AI_INPUT_MESSAGES][0]["content"]
         )
-        assert "5" in chat_spans[0]["data"]["ai.responses"]
-        assert "word" in tool_exec_span["data"]["ai.input_messages"]
-        assert 5 == int(tool_exec_span["data"]["ai.responses"])
+        assert "5" in chat_spans[0]["data"][SPANDATA.AI_RESPONSES]
+        assert "word" in tool_exec_span["data"][SPANDATA.AI_INPUT_MESSAGES]
+        assert 5 == int(tool_exec_span["data"][SPANDATA.AI_RESPONSES])
         assert (
             "You are very powerful"
-            in chat_spans[1]["data"]["ai.input_messages"][0]["content"]
+            in chat_spans[1]["data"][SPANDATA.AI_INPUT_MESSAGES][0]["content"]
         )
-        assert "5" in chat_spans[1]["data"]["ai.responses"]
+        assert "5" in chat_spans[1]["data"][SPANDATA.AI_RESPONSES]
     else:
-        assert "ai.input_messages" not in chat_spans[0].get("data", {})
-        assert "ai.responses" not in chat_spans[0].get("data", {})
-        assert "ai.input_messages" not in chat_spans[1].get("data", {})
-        assert "ai.responses" not in chat_spans[1].get("data", {})
-        assert "ai.input_messages" not in tool_exec_span.get("data", {})
-        assert "ai.responses" not in tool_exec_span.get("data", {})
+        assert SPANDATA.AI_INPUT_MESSAGES not in chat_spans[0].get("data", {})
+        assert SPANDATA.AI_RESPONSES not in chat_spans[0].get("data", {})
+        assert SPANDATA.AI_INPUT_MESSAGES not in chat_spans[1].get("data", {})
+        assert SPANDATA.AI_RESPONSES not in chat_spans[1].get("data", {})
+        assert SPANDATA.AI_INPUT_MESSAGES not in tool_exec_span.get("data", {})
+        assert SPANDATA.AI_RESPONSES not in tool_exec_span.get("data", {})
 
 
 def test_langchain_error(sentry_init, capture_events):
diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py
index 011192e49f..3fdc138f39 100644
--- a/tests/integrations/openai/test_openai.py
+++ b/tests/integrations/openai/test_openai.py
@@ -7,6 +7,7 @@
 from openai.types.create_embedding_response import Usage as EmbeddingTokenUsage
 
 from sentry_sdk import start_transaction
+from sentry_sdk.consts import SPANDATA
 from sentry_sdk.integrations.openai import (
     OpenAIIntegration,
     _calculate_chat_completion_usage,
@@ -83,11 +84,11 @@ def test_nonstreaming_chat_completion(
     assert span["op"] == "ai.chat_completions.create.openai"
 
     if send_default_pii and include_prompts:
-        assert "hello" in span["data"]["ai.input_messages"]["content"]
-        assert "the model response" in span["data"]["ai.responses"]["content"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES]["content"]
+        assert "the model response" in span["data"][SPANDATA.AI_RESPONSES]["content"]
     else:
-        assert "ai.input_messages" not in span["data"]
-        assert "ai.responses" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
+        assert SPANDATA.AI_RESPONSES not in span["data"]
 
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 10
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 20
@@ -125,11 +126,11 @@ async def test_nonstreaming_chat_completion_async(
     assert span["op"] == "ai.chat_completions.create.openai"
 
     if send_default_pii and include_prompts:
-        assert "hello" in span["data"]["ai.input_messages"]["content"]
-        assert "the model response" in span["data"]["ai.responses"]["content"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES]["content"]
+        assert "the model response" in span["data"][SPANDATA.AI_RESPONSES]["content"]
     else:
-        assert "ai.input_messages" not in span["data"]
-        assert "ai.responses" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
+        assert SPANDATA.AI_RESPONSES not in span["data"]
 
     assert span["measurements"]["ai_completion_tokens_used"]["value"] == 10
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 20
@@ -218,11 +219,11 @@ def test_streaming_chat_completion(
     assert span["op"] == "ai.chat_completions.create.openai"
 
     if send_default_pii and include_prompts:
-        assert "hello" in span["data"]["ai.input_messages"]["content"]
-        assert "hello world" in span["data"]["ai.responses"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES]["content"]
+        assert "hello world" in span["data"][SPANDATA.AI_RESPONSES]
     else:
-        assert "ai.input_messages" not in span["data"]
-        assert "ai.responses" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
+        assert SPANDATA.AI_RESPONSES not in span["data"]
 
     try:
         import tiktoken  # type: ignore # noqa # pylint: disable=unused-import
@@ -314,11 +315,11 @@ async def test_streaming_chat_completion_async(
     assert span["op"] == "ai.chat_completions.create.openai"
 
     if send_default_pii and include_prompts:
-        assert "hello" in span["data"]["ai.input_messages"]["content"]
-        assert "hello world" in span["data"]["ai.responses"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES]["content"]
+        assert "hello world" in span["data"][SPANDATA.AI_RESPONSES]
     else:
-        assert "ai.input_messages" not in span["data"]
-        assert "ai.responses" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
+        assert SPANDATA.AI_RESPONSES not in span["data"]
 
     try:
         import tiktoken  # type: ignore # noqa # pylint: disable=unused-import
@@ -404,9 +405,9 @@ def test_embeddings_create(
     span = tx["spans"][0]
     assert span["op"] == "ai.embeddings.create.openai"
     if send_default_pii and include_prompts:
-        assert "hello" in span["data"]["ai.input_messages"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES]
     else:
-        assert "ai.input_messages" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
 
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 20
     assert span["measurements"]["ai_total_tokens_used"]["value"] == 30
@@ -452,9 +453,9 @@ async def test_embeddings_create_async(
     span = tx["spans"][0]
     assert span["op"] == "ai.embeddings.create.openai"
     if send_default_pii and include_prompts:
-        assert "hello" in span["data"]["ai.input_messages"]
+        assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES]
     else:
-        assert "ai.input_messages" not in span["data"]
+        assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
 
     assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 20
     assert span["measurements"]["ai_total_tokens_used"]["value"] == 30