Skip to content
219 changes: 188 additions & 31 deletions newrelic/hooks/external_botocore.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from conftest import BOTOCORE_VERSION
from testing_support.fixtures import override_llm_token_callback_settings, reset_core_stats_engine, validate_attributes
from testing_support.ml_testing_utils import (
add_token_count_to_events,
add_token_counts_to_chat_events,
disabled_ai_monitoring_record_content_settings,
disabled_ai_monitoring_settings,
events_sans_content,
Expand Down Expand Up @@ -49,6 +49,9 @@
"duration": None, # Response time varies each test run
"request.model": "anthropic.claude-3-sonnet-20240229-v1:0",
"response.model": "anthropic.claude-3-sonnet-20240229-v1:0",
"response.usage.prompt_tokens": 26,
"response.usage.completion_tokens": 100,
"response.usage.total_tokens": 126,
"request.temperature": 0.7,
"request.max_tokens": 100,
"response.choices.finish_reason": "max_tokens",
Expand All @@ -70,6 +73,7 @@
"role": "system",
"completion_id": None,
"sequence": 0,
"token_count": 0,
"response.model": "anthropic.claude-3-sonnet-20240229-v1:0",
"vendor": "bedrock",
"ingest_source": "Python",
Expand All @@ -88,6 +92,7 @@
"role": "user",
"completion_id": None,
"sequence": 1,
"token_count": 0,
"response.model": "anthropic.claude-3-sonnet-20240229-v1:0",
"vendor": "bedrock",
"ingest_source": "Python",
Expand All @@ -106,6 +111,7 @@
"role": "assistant",
"completion_id": None,
"sequence": 2,
"token_count": 0,
"response.model": "anthropic.claude-3-sonnet-20240229-v1:0",
"vendor": "bedrock",
"ingest_source": "Python",
Expand Down Expand Up @@ -189,7 +195,7 @@ def _test():
@reset_core_stats_engine()
@override_llm_token_callback_settings(llm_token_count_callback)
def test_bedrock_chat_completion_with_token_count(set_trace_info, exercise_model):
@validate_custom_events(add_token_count_to_events(chat_completion_expected_events))
@validate_custom_events(add_token_counts_to_chat_events(chat_completion_expected_events))
# One summary event, one user message, and one response message from the assistant
@validate_custom_event_count(count=4)
@validate_transaction_metrics(
Expand Down Expand Up @@ -476,46 +482,3 @@ def _test():
converse_invalid_model(loop, bedrock_converse_server)

_test()


@reset_core_stats_engine()
@override_llm_token_callback_settings(llm_token_count_callback)
def test_bedrock_chat_completion_error_incorrect_access_key_with_token_count(
monkeypatch, bedrock_converse_server, loop, set_trace_info
):
"""
A request is made to the server with invalid credentials. botocore will reach out to the server and receive an
UnrecognizedClientException as a response. Information from the request will be parsed and reported in customer
events. The error response can also be parsed, and will be included as attributes on the recorded exception.
"""

@validate_custom_events(add_token_count_to_events(chat_completion_invalid_access_key_error_events))
@validate_error_trace_attributes(
_client_error_name,
exact_attrs={
"agent": {},
"intrinsic": {},
"user": {
"http.statusCode": 403,
"error.message": "The security token included in the request is invalid.",
"error.code": "UnrecognizedClientException",
},
},
)
@validate_transaction_metrics(
name="test_bedrock_chat_completion_incorrect_access_key_with_token_count",
scoped_metrics=[("Llm/completion/Bedrock/converse", 1)],
rollup_metrics=[("Llm/completion/Bedrock/converse", 1)],
custom_metrics=[(f"Supportability/Python/ML/Bedrock/{BOTOCORE_VERSION}", 1)],
background_task=True,
)
@background_task(name="test_bedrock_chat_completion_incorrect_access_key_with_token_count")
def _test():
set_trace_info()
add_custom_attribute("llm.conversation_id", "my-awesome-id")
add_custom_attribute("llm.foo", "bar")
add_custom_attribute("non_llm_attr", "python-agent")

converse_incorrect_access_key(loop, bedrock_converse_server, monkeypatch)

_test()
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
)
from testing_support.fixtures import override_llm_token_callback_settings, reset_core_stats_engine, validate_attributes
from testing_support.ml_testing_utils import (
add_token_count_to_events,
add_token_counts_to_chat_events,
add_token_count_streaming_events,
disabled_ai_monitoring_record_content_settings,
disabled_ai_monitoring_settings,
disabled_ai_monitoring_streaming_settings,
Expand Down Expand Up @@ -206,7 +207,7 @@ def _test():
@reset_core_stats_engine()
@override_llm_token_callback_settings(llm_token_count_callback)
def test_bedrock_chat_completion_with_token_count(set_trace_info, exercise_model, expected_events, expected_metrics):
@validate_custom_events(add_token_count_to_events(expected_events))
@validate_custom_events(add_token_counts_to_chat_events((add_token_count_streaming_events(expected_events))))
# One summary event, one user message, and one response message from the assistant
@validate_custom_event_count(count=3)
@validate_transaction_metrics(
Expand Down Expand Up @@ -455,51 +456,6 @@ def _test():
_test()


@reset_core_stats_engine()
@override_llm_token_callback_settings(llm_token_count_callback)
def test_bedrock_chat_completion_error_incorrect_access_key_with_token(
monkeypatch,
bedrock_server,
exercise_model,
set_trace_info,
expected_invalid_access_key_error_events,
expected_metrics,
):
@validate_custom_events(add_token_count_to_events(expected_invalid_access_key_error_events))
@validate_error_trace_attributes(
_client_error_name,
exact_attrs={
"agent": {},
"intrinsic": {},
"user": {
"http.statusCode": 403,
"error.message": "The security token included in the request is invalid.",
"error.code": "UnrecognizedClientException",
},
},
)
@validate_transaction_metrics(
name="test_bedrock_chat_completion",
scoped_metrics=expected_metrics,
rollup_metrics=expected_metrics,
custom_metrics=[(f"Supportability/Python/ML/Bedrock/{BOTOCORE_VERSION}", 1)],
background_task=True,
)
@background_task(name="test_bedrock_chat_completion")
def _test():
monkeypatch.setattr(bedrock_server._request_signer._credentials, "access_key", "INVALID-ACCESS-KEY")

with pytest.raises(_client_error): # not sure where this exception actually comes from
set_trace_info()
add_custom_attribute("llm.conversation_id", "my-awesome-id")
add_custom_attribute("llm.foo", "bar")
add_custom_attribute("non_llm_attr", "python-agent")

exercise_model(prompt="Invalid Token", temperature=0.7, max_tokens=100)

_test()


def invoke_model_malformed_request_body(loop, bedrock_server, response_streaming):
async def _coro():
with pytest.raises(_client_error):
Expand Down Expand Up @@ -798,58 +754,6 @@ async def _test():
loop.run_until_complete(_test())


@reset_core_stats_engine()
@override_llm_token_callback_settings(llm_token_count_callback)
@validate_custom_events(add_token_count_to_events(chat_completion_expected_streaming_error_events))
@validate_custom_event_count(count=2)
@validate_error_trace_attributes(
_event_stream_error_name,
exact_attrs={
"agent": {},
"intrinsic": {},
"user": {
"error.message": "Malformed input request, please reformat your input and try again.",
"error.code": "ValidationException",
},
},
forgone_params={"agent": (), "intrinsic": (), "user": ("http.statusCode")},
)
@validate_transaction_metrics(
name="test_bedrock_chat_completion",
scoped_metrics=[("Llm/completion/Bedrock/invoke_model_with_response_stream", 1)],
rollup_metrics=[("Llm/completion/Bedrock/invoke_model_with_response_stream", 1)],
custom_metrics=[(f"Supportability/Python/ML/Bedrock/{BOTOCORE_VERSION}", 1)],
background_task=True,
)
@background_task(name="test_bedrock_chat_completion")
def test_bedrock_chat_completion_error_streaming_exception_with_token_count(loop, bedrock_server, set_trace_info):
"""
Duplicate of test_bedrock_chat_completion_error_streaming_exception, but with token callback being set.

See the original test for a description of the error case.
"""

async def _test():
with pytest.raises(_event_stream_error):
model = "amazon.titan-text-express-v1"
body = (chat_completion_payload_templates[model] % ("Streaming Exception", 0.7, 100)).encode("utf-8")

set_trace_info()
add_custom_attribute("llm.conversation_id", "my-awesome-id")
add_custom_attribute("llm.foo", "bar")
add_custom_attribute("non_llm_attr", "python-agent")

response = await bedrock_server.invoke_model_with_response_stream(
body=body, modelId=model, accept="application/json", contentType="application/json"
)

body = response.get("body")
async for resp in body:
assert resp

loop.run_until_complete(_test())


def test_bedrock_chat_completion_functions_marked_as_wrapped_for_sdk_compatibility(bedrock_server):
assert bedrock_server._nr_wrapped

Expand Down
43 changes: 2 additions & 41 deletions tests/external_aiobotocore/test_bedrock_embeddings.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
)
from testing_support.fixtures import override_llm_token_callback_settings, reset_core_stats_engine, validate_attributes
from testing_support.ml_testing_utils import (
add_token_count_to_events,
add_token_count_to_embedding_events,
disabled_ai_monitoring_record_content_settings,
disabled_ai_monitoring_settings,
events_sans_content,
Expand Down Expand Up @@ -164,7 +164,7 @@ def _test():
@reset_core_stats_engine()
@override_llm_token_callback_settings(llm_token_count_callback)
def test_bedrock_embedding_with_token_count(set_trace_info, exercise_model, expected_events):
@validate_custom_events(add_token_count_to_events(expected_events))
@validate_custom_events(add_token_count_to_embedding_events(expected_events))
@validate_custom_event_count(count=1)
@validate_transaction_metrics(
name="test_bedrock_embedding",
Expand Down Expand Up @@ -289,45 +289,6 @@ def _test():
_test()


@reset_core_stats_engine()
@override_llm_token_callback_settings(llm_token_count_callback)
def test_bedrock_embedding_error_incorrect_access_key_with_token_count(
monkeypatch, bedrock_server, exercise_model, set_trace_info, expected_invalid_access_key_error_events
):
@validate_custom_events(add_token_count_to_events(expected_invalid_access_key_error_events))
@validate_error_trace_attributes(
_client_error_name,
exact_attrs={
"agent": {},
"intrinsic": {},
"user": {
"http.statusCode": 403,
"error.message": "The security token included in the request is invalid.",
"error.code": "UnrecognizedClientException",
},
},
)
@validate_transaction_metrics(
name="test_bedrock_embedding",
scoped_metrics=[("Llm/embedding/Bedrock/invoke_model", 1)],
rollup_metrics=[("Llm/embedding/Bedrock/invoke_model", 1)],
background_task=True,
)
@background_task(name="test_bedrock_embedding")
def _test():
monkeypatch.setattr(bedrock_server._request_signer._credentials, "access_key", "INVALID-ACCESS-KEY")

with pytest.raises(_client_error): # not sure where this exception actually comes from
set_trace_info()
add_custom_attribute("llm.conversation_id", "my-awesome-id")
add_custom_attribute("llm.foo", "bar")
add_custom_attribute("non_llm_attr", "python-agent")

exercise_model(prompt="Invalid Token")

_test()


@reset_core_stats_engine()
@validate_custom_events(embedding_expected_malformed_request_body_events)
@validate_custom_event_count(count=1)
Expand Down
Loading
Loading