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/)_. -[](https://discord.gg/wdNEHETs87) +[](https://discord.com/invite/Ww9hbqr) [](https://twitter.com/intent/follow?screen_name=getsentry) [](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