@@ -384,6 +384,9 @@ async def make_bedrock_api_request(
384
384
)
385
385
#########################################################
386
386
if response .status_code == 200 :
387
+ # check if the response contains an error
388
+ if self ._check_bedrock_response_for_exception (response = response ):
389
+ raise self ._get_http_exception_for_failed_guardrail (response )
387
390
# check if the response was flagged
388
391
_json_response = response .json ()
389
392
redacted_response = _redact_pii_matches (_json_response )
@@ -404,16 +407,64 @@ async def make_bedrock_api_request(
404
407
405
408
return bedrock_guardrail_response
406
409
410
+ def _check_bedrock_response_for_exception (self , response ) -> bool :
411
+ """
412
+ Return True if the Bedrock ApplyGuardrail response indicates an exception.
413
+
414
+ Works with real httpx.Response objects and MagicMock responses used in tests.
415
+ """
416
+ payload = None
417
+
418
+ try :
419
+ json_method = getattr (response , "json" , None )
420
+ if callable (json_method ):
421
+ payload = json_method ()
422
+ except Exception :
423
+ payload = None
424
+
425
+ if payload is None :
426
+ try :
427
+ raw = getattr (response , "content" , None )
428
+ if isinstance (raw , (bytes , bytearray )):
429
+ payload = json .loads (raw .decode ("utf-8" ))
430
+ else :
431
+ text = getattr (response , "text" , None )
432
+ if isinstance (text , str ):
433
+ payload = json .loads (text )
434
+ except Exception :
435
+ # Can't parse -> assume no explicit Exception marker
436
+ return False
437
+
438
+ if not isinstance (payload , dict ):
439
+ return False
440
+
441
+ return "Exception" in payload .get ("Output" , {}).get ("__type" , "" )
442
+
407
443
def _get_bedrock_guardrail_response_status (
408
444
self , response : httpx .Response
409
445
) -> Literal ["success" , "failure" ]:
410
446
"""
411
447
Get the status of the bedrock guardrail response.
412
448
"""
413
449
if response .status_code == 200 :
450
+ if self ._check_bedrock_response_for_exception (response ):
451
+ return "failure"
414
452
return "success"
415
453
return "failure"
416
454
455
+ def _get_http_exception_for_failed_guardrail (
456
+ self , response : httpx .Response
457
+ ) -> HTTPException :
458
+ return HTTPException (
459
+ status_code = 400 ,
460
+ detail = {
461
+ "error" : "Guardrail application failed." ,
462
+ "bedrock_guardrail_response" : json .loads (
463
+ response .content .decode ("utf-8" )
464
+ ).get ("Output" , {}),
465
+ },
466
+ )
467
+
417
468
def _get_http_exception_for_blocked_guardrail (
418
469
self , response : BedrockGuardrailResponse
419
470
) -> HTTPException :
@@ -562,11 +613,11 @@ async def async_pre_call_hook(
562
613
#########################################################
563
614
########## 2. Update the messages with the guardrail response ##########
564
615
#########################################################
565
- data ["messages" ] = (
566
- self . _update_messages_with_updated_bedrock_guardrail_response (
567
- messages = new_messages ,
568
- bedrock_guardrail_response = bedrock_guardrail_response ,
569
- )
616
+ data [
617
+ "messages"
618
+ ] = self . _update_messages_with_updated_bedrock_guardrail_response (
619
+ messages = new_messages ,
620
+ bedrock_guardrail_response = bedrock_guardrail_response ,
570
621
)
571
622
572
623
#########################################################
@@ -617,11 +668,11 @@ async def async_moderation_hook(
617
668
#########################################################
618
669
########## 2. Update the messages with the guardrail response ##########
619
670
#########################################################
620
- data ["messages" ] = (
621
- self . _update_messages_with_updated_bedrock_guardrail_response (
622
- messages = new_messages ,
623
- bedrock_guardrail_response = bedrock_guardrail_response ,
624
- )
671
+ data [
672
+ "messages"
673
+ ] = self . _update_messages_with_updated_bedrock_guardrail_response (
674
+ messages = new_messages ,
675
+ bedrock_guardrail_response = bedrock_guardrail_response ,
625
676
)
626
677
627
678
#########################################################
0 commit comments