diff --git a/sentry_sdk/integrations/boto3/_services/bedrock.py b/sentry_sdk/integrations/boto3/_services/bedrock.py index e6e1446aa3..94554d1df7 100644 --- a/sentry_sdk/integrations/boto3/_services/bedrock.py +++ b/sentry_sdk/integrations/boto3/_services/bedrock.py @@ -28,12 +28,31 @@ def get_request_attributes(self, ctx: "AwsCallContext") -> "Attributes": if ctx.operation_name != "Converse" and ctx.operation_name != "ConverseStream": return {} - return { + attributes: "Attributes" = { SPANDATA.GEN_AI_PROVIDER_NAME: "aws.bedrock", SPANDATA.GEN_AI_OPERATION_NAME: "chat", SPANDATA.GEN_AI_RESPONSE_STREAMING: ctx.operation_name == "ConverseStream", } + inference_config = ctx.params.get("inferenceConfig") + + if not isinstance(inference_config, dict): + return attributes + + max_tokens = inference_config.get("maxTokens") + if max_tokens is not None: + attributes[SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] = max_tokens + + temperature = inference_config.get("temperature") + if temperature is not None: + attributes[SPANDATA.GEN_AI_REQUEST_TEMPERATURE] = temperature + + top_p = inference_config.get("topP") + if top_p is not None: + attributes[SPANDATA.GEN_AI_REQUEST_TOP_P] = top_p + + return attributes + def get_response_attributes( self, ctx: "AwsCallContext", diff --git a/tests/integrations/boto3/test_bedrock.py b/tests/integrations/boto3/test_bedrock.py index 5219bdf8b2..96131f723b 100644 --- a/tests/integrations/boto3/test_bedrock.py +++ b/tests/integrations/boto3/test_bedrock.py @@ -55,6 +55,11 @@ def test_converse( client.converse( modelId="anthropic.claude-3-sonnet-20240229-v1:0", messages=[{"role": "user", "content": [{"text": "Hi"}]}], + inferenceConfig={ + "maxTokens": 1024, + "temperature": 0.7, + "topP": 0.9, + }, ) sentry_sdk.flush() @@ -68,6 +73,10 @@ def test_converse( assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "aws.bedrock" assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 else: events = capture_events() @@ -75,6 +84,11 @@ def test_converse( client.converse( modelId="anthropic.claude-3-sonnet-20240229-v1:0", messages=[{"role": "user", "content": [{"text": "Hi"}]}], + inferenceConfig={ + "maxTokens": 1024, + "temperature": 0.7, + "topP": 0.9, + }, ) (transaction,) = events @@ -84,6 +98,10 @@ def test_converse( assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + @pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @@ -127,6 +145,11 @@ def raise_client_error(**kwargs): client.converse( modelId="anthropic.claude-3-sonnet-20240229-v1:0", messages=[{"role": "user", "content": [{"text": "Hi"}]}], + inferenceConfig={ + "maxTokens": 1024, + "temperature": 0.7, + "topP": 0.9, + }, ) sentry_sdk.flush() @@ -140,6 +163,10 @@ def raise_client_error(**kwargs): assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "aws.bedrock" assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.ERROR_TYPE] == "AccessDeniedException" assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 403 assert span["attributes"][SPANDATA.AWS_REQUEST_ID] == "test-id" @@ -152,6 +179,11 @@ def raise_client_error(**kwargs): client.converse( modelId="anthropic.claude-3-sonnet-20240229-v1:0", messages=[{"role": "user", "content": [{"text": "Hi"}]}], + inferenceConfig={ + "maxTokens": 1024, + "temperature": 0.7, + "topP": 0.9, + }, ) (transaction,) = events @@ -160,6 +192,10 @@ def raise_client_error(**kwargs): assert span["data"][SPANDATA.GEN_AI_PROVIDER_NAME] == "aws.bedrock" assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["data"][SPANDATA.ERROR_TYPE] == "AccessDeniedException" assert span["data"][SPANDATA.HTTP_STATUS_CODE] == 403 assert span["data"][SPANDATA.AWS_REQUEST_ID] == "test-id" @@ -193,6 +229,11 @@ def test_converse_stream( client.converse_stream( modelId="anthropic.claude-3-sonnet-20240229-v1:0", messages=[{"role": "user", "content": [{"text": "Hi"}]}], + inferenceConfig={ + "maxTokens": 1024, + "temperature": 0.7, + "topP": 0.9, + }, ) sentry_sdk.flush() @@ -206,6 +247,10 @@ def test_converse_stream( assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "aws.bedrock" assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 else: events = capture_events() @@ -213,6 +258,11 @@ def test_converse_stream( client.converse_stream( modelId="anthropic.claude-3-sonnet-20240229-v1:0", messages=[{"role": "user", "content": [{"text": "Hi"}]}], + inferenceConfig={ + "maxTokens": 1024, + "temperature": 0.7, + "topP": 0.9, + }, ) (transaction,) = events @@ -222,6 +272,10 @@ def test_converse_stream( assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + @pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @@ -265,6 +319,11 @@ def raise_client_error(**kwargs): client.converse_stream( modelId="anthropic.claude-3-sonnet-20240229-v1:0", messages=[{"role": "user", "content": [{"text": "Hi"}]}], + inferenceConfig={ + "maxTokens": 1024, + "temperature": 0.7, + "topP": 0.9, + }, ) sentry_sdk.flush() @@ -279,6 +338,10 @@ def raise_client_error(**kwargs): assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.ERROR_TYPE] == "AccessDeniedException" assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 403 assert span["attributes"][SPANDATA.AWS_REQUEST_ID] == "test-id" @@ -291,6 +354,11 @@ def raise_client_error(**kwargs): client.converse_stream( modelId="anthropic.claude-3-sonnet-20240229-v1:0", messages=[{"role": "user", "content": [{"text": "Hi"}]}], + inferenceConfig={ + "maxTokens": 1024, + "temperature": 0.7, + "topP": 0.9, + }, ) (transaction,) = events @@ -300,6 +368,10 @@ def raise_client_error(**kwargs): assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["data"][SPANDATA.ERROR_TYPE] == "AccessDeniedException" assert span["data"][SPANDATA.HTTP_STATUS_CODE] == 403 assert span["data"][SPANDATA.AWS_REQUEST_ID] == "test-id"