11# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22# SPDX-License-Identifier: Apache-2.0
33from logging import INFO , Logger , getLogger
4+ import math
45from typing import Dict , List
56
67from docker .types import EndpointConfig
3738_GEN_AI_REQUEST_TEMPERATURE : str = "gen_ai.request.temperature"
3839_GEN_AI_REQUEST_TOP_P : str = "gen_ai.request.top_p"
3940_GEN_AI_REQUEST_MAX_TOKENS : str = "gen_ai.request.max_tokens"
40-
41+ _GEN_AI_RESPONSE_FINISH_REASONS : str = "gen_ai.response.finish_reasons"
42+ _GEN_AI_USAGE_INPUT_TOKENS : str = 'gen_ai.usage.input_tokens'
43+ _GEN_AI_USAGE_OUTPUT_TOKENS : str = 'gen_ai.usage.output_tokens'
4144
4245# pylint: disable=too-many-public-methods
4346class AWSSDKTest (ContractTestBase ):
@@ -410,7 +413,7 @@ def test_kinesis_fault(self):
410413 )
411414
412415 def test_bedrock_runtime_invoke_model_amazon_titan (self ):
413- self .do_test_requests (
416+ result = self .do_test_requests (
414417 "bedrock/invokemodel/invoke-model/amazon.titan-text-premier-v1:0" ,
415418 "GET" ,
416419 200 ,
@@ -428,9 +431,15 @@ def test_bedrock_runtime_invoke_model_amazon_titan(self):
428431 _GEN_AI_REQUEST_TEMPERATURE : 0.7 ,
429432 _GEN_AI_REQUEST_TOP_P : 0.9
430433 },
434+ response_specific_attributes = {
435+ _GEN_AI_RESPONSE_FINISH_REASONS : ['CONTENT_FILTERED' ],
436+ _GEN_AI_USAGE_INPUT_TOKENS : 15 ,
437+ _GEN_AI_USAGE_OUTPUT_TOKENS : 13
438+ },
439+
431440 span_name = "BedrockRuntime.InvokeModel"
432441 )
433-
442+
434443 def test_bedrock_runtime_invoke_model_anthropic_claude (self ):
435444 self .do_test_requests (
436445 "bedrock/invokemodel/invoke-model/anthropic.claude-v2:1" ,
@@ -450,6 +459,11 @@ def test_bedrock_runtime_invoke_model_anthropic_claude(self):
450459 _GEN_AI_REQUEST_TEMPERATURE : 0.99 ,
451460 _GEN_AI_REQUEST_TOP_P : 1
452461 },
462+ response_specific_attributes = {
463+ _GEN_AI_RESPONSE_FINISH_REASONS : ['end_turn' ],
464+ _GEN_AI_USAGE_INPUT_TOKENS : 15 ,
465+ _GEN_AI_USAGE_OUTPUT_TOKENS : 13
466+ },
453467 span_name = "BedrockRuntime.InvokeModel"
454468 )
455469
@@ -472,6 +486,11 @@ def test_bedrock_runtime_invoke_model_meta_llama(self):
472486 _GEN_AI_REQUEST_TEMPERATURE : 0.5 ,
473487 _GEN_AI_REQUEST_TOP_P : 0.9
474488 },
489+ response_specific_attributes = {
490+ _GEN_AI_RESPONSE_FINISH_REASONS : ['stop' ],
491+ _GEN_AI_USAGE_INPUT_TOKENS : 31 ,
492+ _GEN_AI_USAGE_OUTPUT_TOKENS : 49
493+ },
475494 span_name = "BedrockRuntime.InvokeModel"
476495 )
477496
@@ -494,6 +513,11 @@ def test_bedrock_runtime_invoke_model_cohere_command(self):
494513 _GEN_AI_REQUEST_TEMPERATURE : 0.5 ,
495514 _GEN_AI_REQUEST_TOP_P : 0.65
496515 },
516+ response_specific_attributes = {
517+ _GEN_AI_RESPONSE_FINISH_REASONS : ['COMPLETE' ],
518+ _GEN_AI_USAGE_INPUT_TOKENS : math .ceil (len ("Describe the purpose of a 'hello world' program in one line." ) / 6 ),
519+ _GEN_AI_USAGE_OUTPUT_TOKENS : math .ceil (len ("test-generation-text" ) / 6 )
520+ },
497521 span_name = "BedrockRuntime.InvokeModel"
498522 )
499523
@@ -516,6 +540,11 @@ def test_bedrock_runtime_invoke_model_ai21_jamba(self):
516540 _GEN_AI_REQUEST_TEMPERATURE : 0.6 ,
517541 _GEN_AI_REQUEST_TOP_P : 0.8
518542 },
543+ response_specific_attributes = {
544+ _GEN_AI_RESPONSE_FINISH_REASONS : ['stop' ],
545+ _GEN_AI_USAGE_INPUT_TOKENS : 21 ,
546+ _GEN_AI_USAGE_OUTPUT_TOKENS : 24
547+ },
519548 span_name = "BedrockRuntime.InvokeModel"
520549 )
521550
@@ -538,6 +567,11 @@ def test_bedrock_runtime_invoke_model_mistral_mistral(self):
538567 _GEN_AI_REQUEST_TEMPERATURE : 0.75 ,
539568 _GEN_AI_REQUEST_TOP_P : 0.99
540569 },
570+ response_specific_attributes = {
571+ _GEN_AI_RESPONSE_FINISH_REASONS : ['stop' ],
572+ _GEN_AI_USAGE_INPUT_TOKENS : math .ceil (len ("Describe the purpose of a 'hello world' program in one line." ) / 6 ),
573+ _GEN_AI_USAGE_OUTPUT_TOKENS : math .ceil (len ("test-output-text" ) / 6 )
574+ },
541575 span_name = "BedrockRuntime.InvokeModel"
542576 )
543577
@@ -654,9 +688,6 @@ def test_bedrock_agent_get_data_source(self):
654688 },
655689 span_name = "BedrockAgent.GetDataSource" ,
656690 )
657-
658- # def test_bedrock_agent_runtime_invoke_agent(self):
659- # return None
660691
661692 @override
662693 def _assert_aws_span_attributes (self , resource_scope_spans : List [ResourceScopeSpan ], path : str , ** kwargs ) -> None :
@@ -726,6 +757,7 @@ def _assert_semantic_conventions_span_attributes(
726757 kwargs .get ("remote_operation" ),
727758 status_code ,
728759 kwargs .get ("request_specific_attributes" , {}),
760+ kwargs .get ("response_specific_attributes" , {}),
729761 )
730762
731763 # pylint: disable=unidiomatic-typecheck
@@ -736,6 +768,7 @@ def _assert_semantic_conventions_attributes(
736768 operation : str ,
737769 status_code : int ,
738770 request_specific_attributes : dict ,
771+ response_specific_attributes : dict ,
739772 ) -> None :
740773 attributes_dict : Dict [str , AnyValue ] = self ._get_attributes_dict (attributes_list )
741774 self ._assert_str_attribute (attributes_dict , SpanAttributes .RPC_METHOD , operation )
@@ -744,7 +777,11 @@ def _assert_semantic_conventions_attributes(
744777 self ._assert_int_attribute (attributes_dict , SpanAttributes .HTTP_STATUS_CODE , status_code )
745778 # TODO: aws sdk instrumentation is not respecting PEER_SERVICE
746779 # self._assert_str_attribute(attributes_dict, SpanAttributes.PEER_SERVICE, "backend:8080")
747- for key , value in request_specific_attributes .items ():
780+ self ._assert_specific_attributes (attributes_dict , request_specific_attributes )
781+ self ._assert_specific_attributes (attributes_dict , response_specific_attributes )
782+
783+ def _assert_specific_attributes (self , attributes_dict : Dict [str , AnyValue ], specific_attributes : Dict [str , AnyValue ]) -> None :
784+ for key , value in specific_attributes .items ():
748785 if isinstance (value , str ):
749786 self ._assert_str_attribute (attributes_dict , key , value )
750787 elif isinstance (value , int ):
0 commit comments