From 3e5d585f7d7a761381ec2f1d4d94fed5df85fd8b Mon Sep 17 00:00:00 2001 From: Patrick Lafleur Date: Wed, 1 Oct 2025 11:56:50 -0400 Subject: [PATCH 1/3] Don't run post_call guardrail if no text returned from bedrock --- .../guardrail_hooks/bedrock_guardrails.py | 9 ++++ .../test_bedrock_guardrails.py | 49 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py b/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py index f498d647a5..c88ebe16d9 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py +++ b/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py @@ -727,6 +727,15 @@ class BedrockGuardrail(CustomGuardrail, BaseAWSLLM): ) return + outputs: List[BedrockGuardrailOutput] = ( + response.get("outputs", []) or [] + ) + if not any(output.get("text") for output in outputs): + verbose_proxy_logger.warning( + "Bedrock AI: not running guardrail. No output text in response" + ) + return + ######################################################### ########## 1. Make parallel Bedrock API requests ########## ######################################################### diff --git a/tests/guardrails_tests/test_bedrock_guardrails.py b/tests/guardrails_tests/test_bedrock_guardrails.py index b98a1b16be..1b1fea74af 100644 --- a/tests/guardrails_tests/test_bedrock_guardrails.py +++ b/tests/guardrails_tests/test_bedrock_guardrails.py @@ -1366,3 +1366,52 @@ async def test_bedrock_guardrail_disable_exception_on_block_streaming(): except Exception as e: pytest.fail(f"Should not raise exception when disable_exception_on_block=True in streaming, but got: {e}") + +@pytest.mark.asyncio +async def test_bedrock_guardrail_post_call_success_hook_no_output_text(): + """Test that async_post_call_success_hook skips when there's no output text""" + from unittest.mock import AsyncMock, MagicMock, patch + from litellm.proxy._types import UserAPIKeyAuth + from litellm.types.utils import ModelResponseStream + import litellm + + # Create proper mock objects + mock_user_api_key_dict = UserAPIKeyAuth() + + # Create guardrail instance + guardrail = BedrockGuardrail( + guardrailIdentifier="test-guardrail", + guardrailVersion="DRAFT" + ) + + # Mock Bedrock API response with PII masking + mock_bedrock_response = MagicMock() + mock_bedrock_response.status_code = 200 + mock_bedrock_response.json.return_value = { + "output": { + "message": { + "role": "assistant", + "content": [ + { + "toolUse": { + "toolUseId": "tooluse_kZJMlvQmRJ6eAyJE5GIl7Q", + "name": "top_song", + "input": { + "sign": "WZPZ" + } + } + } + ] + } + }, + "stopReason": "tool_use" + } + + data = {} # request data not used by our condition + mock_user_api_key_dict = UserAPIKeyAuth() + + return await guardrail.async_post_call_success_hook( + data=data, + response=mock_bedrock_response, # dict with "outputs" + user_api_key_dict=mock_user_api_key_dict, + ) \ No newline at end of file From 7ef71d48854d6caaefa87a58c8105cf467151980 Mon Sep 17 00:00:00 2001 From: Patrick Lafleur Date: Wed, 1 Oct 2025 12:08:03 -0400 Subject: [PATCH 2/3] Fix text --- tests/guardrails_tests/test_bedrock_guardrails.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/guardrails_tests/test_bedrock_guardrails.py b/tests/guardrails_tests/test_bedrock_guardrails.py index 1b1fea74af..2997e32f09 100644 --- a/tests/guardrails_tests/test_bedrock_guardrails.py +++ b/tests/guardrails_tests/test_bedrock_guardrails.py @@ -1407,11 +1407,16 @@ async def test_bedrock_guardrail_post_call_success_hook_no_output_text(): "stopReason": "tool_use" } - data = {} # request data not used by our condition + data = { + "model": "gpt-4o", + "messages": [ + {"role": "user", "content": "Hello"}, + ], + } mock_user_api_key_dict = UserAPIKeyAuth() return await guardrail.async_post_call_success_hook( data=data, - response=mock_bedrock_response, # dict with "outputs" + response=mock_bedrock_response, user_api_key_dict=mock_user_api_key_dict, ) \ No newline at end of file From 8e5efd29df85a5533d327223ee5fc3df0823d962 Mon Sep 17 00:00:00 2001 From: Patrick Lafleur Date: Wed, 1 Oct 2025 16:39:26 -0400 Subject: [PATCH 3/3] Fix comment --- tests/guardrails_tests/test_bedrock_guardrails.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/guardrails_tests/test_bedrock_guardrails.py b/tests/guardrails_tests/test_bedrock_guardrails.py index 2997e32f09..c4d1655594 100644 --- a/tests/guardrails_tests/test_bedrock_guardrails.py +++ b/tests/guardrails_tests/test_bedrock_guardrails.py @@ -1384,7 +1384,7 @@ async def test_bedrock_guardrail_post_call_success_hook_no_output_text(): guardrailVersion="DRAFT" ) - # Mock Bedrock API response with PII masking + # Mock Bedrock API with no output text mock_bedrock_response = MagicMock() mock_bedrock_response.status_code = 200 mock_bedrock_response.json.return_value = { @@ -1419,4 +1419,6 @@ async def test_bedrock_guardrail_post_call_success_hook_no_output_text(): data=data, response=mock_bedrock_response, user_api_key_dict=mock_user_api_key_dict, - ) \ No newline at end of file + ) + # If no error is raised, then the test passes + print("✅ No output text in response test passed") \ No newline at end of file