1+ import json
12import pytest
23
34from sentry_sdk .utils import package_version
78except ImportError :
89 NOT_GIVEN = None
910
10- try :
11- from openai import omit
12- except ImportError :
13- omit = None
14-
1511from openai import AsyncOpenAI , OpenAI , AsyncStream , Stream , OpenAIError
1612from openai .types import CompletionUsage , CreateEmbeddingResponse , Embedding
1713from openai .types .chat import ChatCompletion , ChatCompletionMessage , ChatCompletionChunk
4440 OpenAIIntegration ,
4541 _calculate_token_usage ,
4642)
43+ from sentry_sdk .ai .utils import MAX_GEN_AI_MESSAGE_BYTES
44+ from sentry_sdk ._types import AnnotatedValue
45+ from sentry_sdk .serializer import serialize
4746
4847from unittest import mock # python 3.3 and above
4948
@@ -1429,7 +1428,7 @@ async def test_streaming_responses_api_async(
14291428)
14301429@pytest .mark .parametrize (
14311430 "tools" ,
1432- [[], None , NOT_GIVEN , omit ],
1431+ [[], None , NOT_GIVEN ],
14331432)
14341433def test_empty_tools_in_chat_completion (sentry_init , capture_events , tools ):
14351434 sentry_init (
@@ -1456,6 +1455,7 @@ def test_empty_tools_in_chat_completion(sentry_init, capture_events, tools):
14561455
14571456def test_openai_message_role_mapping (sentry_init , capture_events ):
14581457 """Test that OpenAI integration properly maps message roles like 'ai' to 'assistant'"""
1458+
14591459 sentry_init (
14601460 integrations = [OpenAIIntegration (include_prompts = True )],
14611461 traces_sample_rate = 1.0 ,
@@ -1465,7 +1465,6 @@ def test_openai_message_role_mapping(sentry_init, capture_events):
14651465
14661466 client = OpenAI (api_key = "z" )
14671467 client .chat .completions ._post = mock .Mock (return_value = EXAMPLE_CHAT_COMPLETION )
1468-
14691468 # Test messages with mixed roles including "ai" that should be mapped to "assistant"
14701469 test_messages = [
14711470 {"role" : "system" , "content" : "You are helpful." },
@@ -1476,11 +1475,9 @@ def test_openai_message_role_mapping(sentry_init, capture_events):
14761475
14771476 with start_transaction (name = "openai tx" ):
14781477 client .chat .completions .create (model = "test-model" , messages = test_messages )
1479-
1478+ # Verify that the span was created correctly
14801479 (event ,) = events
14811480 span = event ["spans" ][0 ]
1482-
1483- # Verify that the span was created correctly
14841481 assert span ["op" ] == "gen_ai.chat"
14851482 assert SPANDATA .GEN_AI_REQUEST_MESSAGES in span ["data" ]
14861483
@@ -1505,3 +1502,55 @@ def test_openai_message_role_mapping(sentry_init, capture_events):
15051502 # Verify no "ai" roles remain
15061503 roles = [msg ["role" ] for msg in stored_messages ]
15071504 assert "ai" not in roles
1505+
1506+
1507+ def test_openai_message_truncation (sentry_init , capture_events ):
1508+ """Test that large messages are truncated properly in OpenAI integration."""
1509+ sentry_init (
1510+ integrations = [OpenAIIntegration (include_prompts = True )],
1511+ traces_sample_rate = 1.0 ,
1512+ send_default_pii = True ,
1513+ )
1514+ events = capture_events ()
1515+
1516+ client = OpenAI (api_key = "z" )
1517+ client .chat .completions ._post = mock .Mock (return_value = EXAMPLE_CHAT_COMPLETION )
1518+
1519+ large_content = (
1520+ "This is a very long message that will exceed our size limits. " * 1000
1521+ )
1522+ large_messages = [
1523+ {"role" : "system" , "content" : "You are a helpful assistant." },
1524+ {"role" : "user" , "content" : large_content },
1525+ {"role" : "assistant" , "content" : large_content },
1526+ {"role" : "user" , "content" : large_content },
1527+ ]
1528+
1529+ with start_transaction (name = "openai tx" ):
1530+ client .chat .completions .create (
1531+ model = "some-model" ,
1532+ messages = large_messages ,
1533+ )
1534+
1535+ (event ,) = events
1536+ span = event ["spans" ][0 ]
1537+ assert SPANDATA .GEN_AI_REQUEST_MESSAGES in span ["data" ]
1538+
1539+ messages_data = span ["data" ][SPANDATA .GEN_AI_REQUEST_MESSAGES ]
1540+ assert isinstance (messages_data , str )
1541+
1542+ parsed_messages = json .loads (messages_data )
1543+ assert isinstance (parsed_messages , list )
1544+ assert len (parsed_messages ) <= len (large_messages )
1545+
1546+ if "_meta" in event and len (parsed_messages ) < len (large_messages ):
1547+ meta_path = event ["_meta" ]
1548+ if (
1549+ "spans" in meta_path
1550+ and "0" in meta_path ["spans" ]
1551+ and "data" in meta_path ["spans" ]["0" ]
1552+ ):
1553+ span_meta = meta_path ["spans" ]["0" ]["data" ]
1554+ if SPANDATA .GEN_AI_REQUEST_MESSAGES in span_meta :
1555+ messages_meta = span_meta [SPANDATA .GEN_AI_REQUEST_MESSAGES ]
1556+ assert "len" in messages_meta .get ("" , {})
0 commit comments