Ë
    tPêj?Y ã                   ój  — U d dl Z d dlZej                  j                  d e j                  j	                  d«      «       d dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
mZmZmZ d dlmZmZ d dlmZmZ d dlmZmZmZmZmZmZmZmZ d dlZd dlmZ d dlm Z m!Z! d dl"Z"d d	l#m$Z$ d d
l%m&Z& d dl'm(Z( d dl)m*Z* d dl+m,Z, d dl-m.Z. d dl/m0Z0 d dl1m2Z2 d dl3m4Z4 d dl5m6Z6 d dl7m8Z8m9Z9 d dl:m;Z; d dl<m=Z= d dl>m?Z? d dl@mAZAmBZBmCZCmDZDmEZE d dlFmGZG d dlHmIZImJZJ d dlKmLZLmMZM d dlNmOZOmPZPmQZQmRZRmSZSmTZTmUZUmVZVmWZWmXZX d dlYmZZZ erd dl[m\Z\ d dl]m^Z^ d dl_m`Za d d lYmbZbmcZcmdZdmeZemfZfmgZgmhZhmiZimjZjmkZk d!Zleemd"<    end#d$h«      Zoeemd%<   d&Zpeemd'<   d(Zqeemd)<   d*Zreemd+<    ejæ                  d,«      Zteemd-<   d.Zueemd/<   d0Zveemd1<    enh d2£«      Zweemd3<   d4Zxeemd5<   d6d7d8œZyeeze{eTf      emd9<    end:d;h«      Z|eemd<<    G d=„ d>e«      Z} G d?„ d@e«      Z~ G dA„ dBe«      Z G dC„ dDe«      Z€dEezdFezfdG„Z�dHe‚ez   dFe‚ez   fdI„Zƒ G dJ„ dKe,e6«      Z„y)Lé    Nz../..)ÚAsyncGeneratorÚMappingÚSequence)ÚdatetimeÚtimezone)Ú
accumulateÚgroupby)ÚTYPE_CHECKINGÚAnyÚClassVarÚFinalÚLiteralÚ
NamedTupleÚOptionalÚcast)ÚHTTPException)ÚTypeAdapterÚValidationError)Úverbose_proxy_logger)Ú	DualCache)Ú*BEDROCK_APPLY_GUARDRAIL_CHUNK_BUDGET_CHARS)ÚModifyResponseException)ÚCustomGuardrail)Ú"redact_nested_match_and_regex_keys)Úbedrock_guardrail_cost)ÚAnthropicMessagesHandler)Ú.effective_scan_only_tool_results_for_guardrail)Ú
BaseAWSLLM)Úget_async_httpx_clientÚhttpxSpecialProvider)ÚUserAPIKeyAuth)Ú _serialize_http_exception_detail)Úkeepalive_ping_has_fired)Ú"anthropic_sse_chunks_from_responseÚanthropic_sse_error_framesÚassemble_anthropic_sse_streamÚis_raw_sse_streamÚmodel_response_text)Úget_secret_str)ÚBedrockChecksConfigModelÚGuardrailEventHooks)ÚAllMessageValuesÚChatCompletionUserMessage)
ÚBedrockChecksMessageÚBedrockChecksViolationÚBedrockContentItemÚBedrockGuardrailChecksResponseÚBedrockGuardrailOutputÚBedrockGuardrailQualifierÚBedrockGuardrailResponseÚBedrockGuardrailUsageÚBedrockRequestÚBedrockTextContent)ÚGenericGuardrailAPIInputs)ÚAWSPreparedRequest©ÚCredentials)ÚLogging)
Ú	CallTypesÚCallTypesLiteralÚChoicesÚGuardrailStatusÚGuardrailTracingDetailÚMessageÚModelResponseÚModelResponseStreamÚStreamingChoicesÚTextChoicesÚbedrockÚGUARDRAIL_NAMEÚcontentÚsourceÚ_BEDROCK_DYNAMIC_BODY_DENYLIST)z	text unitzmaximum input sizezcontent sizeztoo longz	too largezexceeds the maximumÚ#_BEDROCK_TOO_LARGE_ERROR_SUBSTRINGSé   Ú-_BEDROCK_APPLY_GUARDRAIL_MAX_THROTTLE_RETRIESç      à?Ú-_BEDROCK_APPLY_GUARDRAIL_BASE_BACKOFF_SECONDSz\sÚ_BEDROCK_WHITESPACEz/guardrail-checks/invokeÚ%_BEDROCK_INVOKE_GUARDRAIL_CHECKS_PATHé
   Ú"_BEDROCK_CHECKS_MAX_CONTENT_BLOCKS>   ÚpromptAttackÚcontentFilterÚsensitiveInformationÚ_BEDROCK_CHECKS_KNOWN_KEYS)ÚbeginOffsetÚ	endOffsetÚmessageIndexÚcontentIndexÚ!_BEDROCK_CHECKS_PII_LOCATION_KEYSÚgrounding_sourceÚquery)r^   r_   Ú_CONTENT_TYPE_TO_QUALIFIERÚsystemÚ	developerÚ_GROUNDING_SOURCE_TRUSTED_ROLESc                   ó,   — e Zd ZU dZeed<   edz  ed<   y)ÚQualifiedTextBlockzMA piece of message text paired with its Bedrock grounding qualifier (if any).ÚtextNÚ	qualifier)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚstrÚ__annotations__r3   © ó    ú€/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.pyre   re   ‰   s   … ÙWà
ƒIØ(¨4Ñ/Ô/ro   re   c                   óP   — e Zd ZU ee   dz  ed<   ee   dz  ed<   ee   dz  ed<   y)ÚGuardrailMessageFilterResultNÚpayload_messagesÚoriginal_messagesÚtarget_indices)rh   ri   rj   Úlistr,   rm   Úintrn   ro   rp   rr   rr   �   s3   … ØÐ+Ñ,¨tÑ3Ó3ØÐ,Ñ-°Ñ4Ó4Ø˜‘I Ñ$Ô$ro   rr   c                   ó:   — e Zd ZU dZeed<   eedf   ed<   eed<   y)ÚBedrockContentChunkResultaA  One chunk's ApplyGuardrail response, paired with enough bookkeeping to
    reconstruct global masked-output positions once every chunk is back.

    `content` is the exact content items this chunk was called with -- needed
    so an all-clear chunk (empty `outputs`) can still contribute one unmasked
    placeholder per item it covers, keeping every later chunk's masked text
    aligned to its original global position. `fragment_group_size` is 1 for an
    ordinary chunk, and otherwise the total number of consecutive chunk results
    that together make up ONE original content item's own text (split because a
    list of length 1 could not be bisected by list length). All of them must be
    concatenated back into that one item's masked output rather than treated as
    separate items. It is a count rather than a boolean because one item can be
    bisected more than once: two levels of splitting produce four fragments for
    a single item, not two, and grouping them in fixed pairs would emit two
    outputs for one message and shift every later message's masked text.
    Úresponse.rI   Úfragment_group_sizeN)	rh   ri   rj   rk   r4   rm   Útupler0   rw   rn   ro   rp   ry   ry   –   s&   … ñð" 'Ó&ØÐ% sÐ*Ñ+Ó+ØÔro   ry   c                   óZ   — e Zd ZU dZee   dz  ed<   eeef   dz  ed<   e	ed<   dZ
e	ed<   y)ÚApplyGuardrailMessageSelectionzDMessages selected for an apply_guardrail scan + write-back metadata.NÚfiltered_messagesÚscanned_sliceÚscanned_role_subsetFÚ	skip_scan)rh   ri   rj   rk   rv   r,   rm   r|   rw   Úboolr‚   rn   ro   rp   r~   r~   ­   s;   … ÙNàÐ,Ñ-°Ñ4Ó4ð ˜˜c˜‘? TÑ)Ó)àÓà€IˆtÔro   r~   Úresponse_jsonÚreturnc                 ó@   — t        | «      }t        |t        «      r|S | S )zì
    Redact match-like fields from a Bedrock ApplyGuardrail JSON payload.

    Delegates to :func:`redact_nested_match_and_regex_keys` (same rules as spend
    logging). Kept as a Bedrock-module entry point for existing unit tests.
    )r   Ú
isinstanceÚdict)r„   Úredacteds     rp   Ú_redact_pii_matchesrŠ   º   s"   € ô 9¸ÓG€HÜ! (¬DÔ1ˆ8ÐD°}ÐDro   Úassessmentsc                 ó@   — t        | «      }t        |t        «      r|S | S )zÿ
    Redact sensitive match-like fields from blocked assessment summaries.

    This is used for customer-visible error payloads (HTTPException.detail) where
    we want to preserve policy/type/action metadata without echoing raw matched
    content.
    )r   r‡   rv   )r‹   r‰   s     rp   Ú_redact_assessment_match_fieldsr�   Å   s"   € ô 9¸ÓE€HÜ! (¬DÔ1ˆ8ÐB°{ÐBro   c                   óÆ  ‡ — e Zd ZU dZee   ed<   dddddddefdedz  dedz  dedz  d	e	e
eef   z  dz  d
edz  dedz  dedz  defˆ fd„Zedee   fd„«       Zed	e	e
eef   z  dz  deeef   dz  fd„«       Zdee   dz  defd„Z	 d“deez  dee   dz  defd„Zdeez  dedee   fd„Z	 	 d”ded   dee   dz  deez  dz  defd„Zdedee    dz  fd„Z!de defd„Z"dee   dz  dee    fd„Z#defd „Z$dee   dz  de%fd!„Z&dee   d"ededz  fd#„Z'ededefd$„«       Z(d%ee   d&ed'ee   de)eef   dz  fd(„Z*d'ee   d)d*d+ed,ed-   de+f
d.„Z,d/ed'ed0e)eef   dz  d1edef
d2„Z-d3ee   dz  d4ee   d5ee   dz  dee   fd6„Z.d7„ Z/	 	 	 d•d8ed9ed:ed;edz  d<edz  d=edz  fd>„Z0	 	 	 	 d–ded   dee   dz  de1j4                  dz  d+edz  d?edz  de2fd@„Z3	 	 	 	 d–ded   dee   dz  de1j4                  dz  d+edz  d?edz  de2fdA„Z4dBe5e   dCe
eef   dDdEd:ed;edz  d+edz  dFedGdHdIedJee6   de)e7dKf   fdL„Z8dBe5e   dCe
eef   dDdEd:ed;edz  d+edz  dFedGdHdJee6   de2fdM„Z9dBe5e   dCe
eef   dDdEd:ed;edz  d+edz  dFedGdHdJee6   de2fdN„Z:dOe;jx                  dPed+edz  dFedGdHd:edz  dJe5e6   ddfdQ„Z=dRe2d+edz  dFedGdHd:edz  ddfdS„Z>dTed+edz  dFedGdHd:edz  dJe5e6   ddfdU„Z?edBe5e   defdV„«       Z@edBe5e   dWede)e)edKf   dKf   fdX„«       ZAedBe5e   de)e)edKf   e)edKf   f   dz  fdY„«       ZBedZedefd[„«       ZCedTedefd\„«       ZDed]e5e7   de2fd^„«       ZEed]e5e7   de6fd_„«       ZFed`e5e6   de6fda„«       ZGed]e5e7   de)e)e7dKf   dKf   fdb„«       ZHedce)e7dKf   de)e)eIdKf   ef   fdd„«       ZJ	 d—dedfd+edz  dFedGdHdgede;jx                  fdh„ZKediedj   d'ee   deeL   fdk„«       ZM	 	 d”ded   dee   dz  de1j4                  dz  deeL   fdl„ZN	 	 	 	 d–ded   dee   dz  de1j4                  dz  d+edz  d?edz  de2fdm„ZOdePdz  deeQ   fdn„ZRedePdeeef   fdo„«       ZSedpedeTfdq„«       ZUedreeQ   deVfds„«       ZW	 d“dreeQ   d+edz  deXeYz  fdt„ZZdefdu„Z[de;jx                  deTfdv„Z\de;jx                  de)eef   fdw„Z]de2d:edz  deVfdx„Z^de2dee   fdy„Z_de2dee   fdz„Z`	 d“de2d+edz  deXeYz  fd{„Zade2defd|„Zbd}ecd~edd8edeedefez  ez  dz  f
d€„Zgd8ed}ecdeefd�„Zhd8ed}ecfd‚„Zidee   dƒe2dee   fd„„Zjd}ecded+edekeldf   fd…„Zmdƒe2dee   fd†„Zndee   d/ee   dee   fd‡„Zodˆee   d/ee   d‰ede)ee   ef   fdŠ„Zpdeez  dƒe2ddfd‹„Zqde1j4                  d/ee   ddfdŒ„Zrededfd�„«       Zsde2defdŽ„Ztd'ee   d)d*d+edeud*   fd�„Zv	 d“d)d*d+ed,ed-   d�eud‘   dd*f
d’„Zwˆ xZxS )˜ÚBedrockGuardrailTÚuse_native_during_call_hookNFrO   ÚguardrailIdentifierÚguardrailVersionÚdisable_exception_on_blockÚchecksÚcontent_filter_thresholdÚprompt_attack_thresholdÚpii_confidence_thresholdÚchunk_budget_charsc	           	      ód  •— t        t        j                  ¬«      | _        || _        || _        d| _        || _        t        |	j                  d«      «      | _
        | j                  |«      | _        || _        || _        || _        |	| _        |xs d| _        	 | j                  �#| j                  €| j
                  �t%        d«      ‚|	j'                  dt)        | j+                  «       «      «       t-        ‰
| �\  di |	¤Ž t1        j.                  | «       | j                  �/t3        | dd«      st3        | dd«      rt5        j6                  d	«       t5        j8                  d
| j                  | j
                  | j                  r(t)        | j                  j;                  «       «      «       y d «       y )N)Úllm_providerrG   Ú)experimental_use_latest_role_message_onlyFz‰Bedrock guardrail accepts either 'guardrailIdentifier'/'guardrailVersion' (ApplyGuardrail) or 'checks' (InvokeGuardrailChecks), not both.Úsupported_event_hooksÚmask_request_contentÚmask_response_contentz‚Bedrock Guardrail: mask_request_content/mask_response_content have no effect with 'checks' (InvokeGuardrailChecks is detect-only).z\Bedrock Guardrail initialized with guardrailIdentifier: %s, guardrailVersion: %s, checks: %srn   )r   r    ÚGuardrailCallbackÚasync_handlerr‘   r’   Úguardrail_providerr˜   rƒ   Úgetr›   Ú_normalize_checksr”   r•   r–   r—   Úoptional_paramsr“   Ú
ValueErrorÚ
setdefaultrv   Úget_supported_event_hooksÚsuperÚ__init__r   Úgetattrr   ÚwarningÚdebugÚkeys)Úselfr‘   r’   r“   r”   r•   r–   r—   r˜   ÚkwargsÚ	__class__s             €rp   r©   zBedrockGuardrail.__init__Ö   s”  ø€ ô 4ÔAU×AgÑAgÔhˆÔØ#6ˆÔ Ø 0ˆÔØ"+ˆÔØ"4ˆÔÜ9=¸f¿j¹jÐItÓ>uÓ9vˆÔ6ð .2×-CÑ-CÀFÓ-KˆŒð )AˆÔ%Ø'>ˆÔ$Ø(@ˆÔ%ð  &ˆÔà0JÒ0SÈeˆÔ'ð	ð �;‰;Ð"¨×(@Ñ(@Ð(LÐPT×PeÑPeÐPqÜðAóð ð 	×ÑÐ1´4¸×8VÑ8VÓ8XÓ3YÔZä‰ÑÑ"˜6Ò"Ü×Ñ˜DÔ!ð �;‰;Ð"Ü�DÐ0°%Ô8¼GÀDÐJaÐchÔ<iä ×(Ñ(ðOôô
 	×"Ñ"ØjØ×$Ñ$Ø×!Ñ!Ø(,¯ªŒD�—‘×!Ñ!Ó#Ó$õ		
ð :>õ		
ro   r…   c                 óœ   — t         j                  t         j                  t         j                  t         j                  t         j
                  gS ©N)r+   Úpre_callÚ	post_callÚduring_callÚpre_mcp_callÚduring_mcp_call)Úclss    rp   r§   z*BedrockGuardrail.get_supported_event_hooks  s;   € ô  ×(Ñ(Ü×)Ñ)Ü×+Ñ+Ü×,Ñ,Ü×/Ñ/ð
ð 	
ro   c                 óê  — | €yt        | t        «      r| j                  d¬«      n
t        | «      }t	        |j                  «       «      t        z
  }|r-t        j                  dt        |«      t        t        «      «       |j                  «       D ��ci c]  \  }}|t        v sŒ|€Œ||“Œ }}}|s8|r6t        dt        |j                  «       «      › dt        t        «      › d�«      ‚|xs dS c c}}w )zþNormalize the configured `checks` into a plain dict for the API body.

        Accepts a pydantic ``BedrockChecksConfigModel`` or a raw dict; drops None /
        unknown keys. Returns None when no usable check is configured (=> ApplyGuardrail).
        NT)Úexclude_nonez�BedrockGuardrail: unrecognized check key(s) %s will be ignored; recognized keys will still be used for InvokeGuardrailChecks. Known keys: %s.zKBedrockGuardrail: 'checks' block contained only unrecognized or empty keys z. Known keys: zS. Fix the guardrail config or remove the 'checks' block to use ApplyGuardrail mode.)r‡   r*   Ú
model_dumprˆ   Úsetr­   rX   r   r«   ÚsortedÚitemsr¥   )r”   ÚrawÚunknown_keysÚkeyÚvalueÚcleaneds         rp   r£   z"BedrockGuardrail._normalize_checks#  sü   € ð ˆ>ØÜ6@ÀÔIaÔ6bˆf×Ñ¨TÐÔ2ÔhlÐmsÓhtˆÜ! #§(¡(£*›oÔ0JÑJˆÙÜ ×(Ñ(ð"ô �|Ó$ÜÔ1Ó2ôð 14·	±	³×w¡* # u¸sÔF`Ò?`ÐejÑev�3˜‘:ÐwˆÑwÙ™3ÜØ]Ô^dÐeh×emÑemÓeoÓ^pÐ]qð rÜ%Ô&@ÓAÐBð Cdðdóð ð
 Š˜$Ðùó xs   ÂC/Â$C/Â'C/Úmessagesc           	      óØ   — t        d¬«      }g }|€|S |D ]M  }| j                  |¬«      }|€Œ|D ]1  }|j                  t        t	        |j
                  ¬«      ¬«      «       Œ3 ŒO ||d<   |S )zS
        Create a bedrock request for the input content - the LLM request.
        ÚINPUT©rJ   ©Úmessage©rf   rI   )r6   Úget_content_items_for_messageÚappendr0   r7   rf   )r®   rÄ   Úbedrock_requestÚbedrock_request_contentrÉ   ÚblocksÚblocks          rp   Ú%_create_bedrock_input_content_requestz6BedrockGuardrail._create_bedrock_input_content_request?  s“   € ô 2@ÀwÔ1OˆØCEÐØÐØ"Ð"Øò 		mˆGØ×7Ñ7ÀÐ7ÓHˆFØˆ~ØØò m�ð
 (×.Ñ.Ô/AÔGYÐ_d×_iÑ_iÔGjÔ/kÕlñmð			mð &=ˆ˜	Ñ"ØÐro   rz   c                 óð   — t        d¬«      }| j                  |«      }|D �cg c]  }| j                  |«      ‘Œ }}t        |«      dkD  }|j	                  | j                  ||¬«      «       ||d<   |S c c}w )aÙ  
        Create a bedrock request for the output content - the LLM response.

        Contextual grounding grades the response against the reference source and
        the user query from the request. When the request tagged any
        ``grounding_source``/``query`` blocks, they are emitted first and the
        response is qualified as ``guard_content`` so Bedrock can score grounding.
        Without such tags the payload is the legacy single response block.
        ÚOUTPUTrÇ   r   )Úhas_groundingrI   )r6   Ú_collect_grounding_blocksÚ_build_content_itemÚlenÚextendÚ_build_response_content_items)r®   rz   rÄ   rÍ   Úgrounding_blocksrÐ   rÎ   rÔ   s           rp   Ú&_create_bedrock_output_content_requestz7BedrockGuardrail._create_bedrock_output_content_requestU  s’   € ô 2@ÀxÔ1PˆØ"&×"@Ñ"@ÀÓ"JÐà9IöD
Ø05ˆD×$Ñ$ UÕ+ðD
Ðð D
ô  #Ð#:Ó;¸aÑ?ˆð 	 ×&Ñ& t×'IÑ'IÈ(ÐboÐ'IÓ'pÔqØ%<ˆ˜	Ñ"ØÐùòD
s   ¢A3rÔ   c                 óœ  — g }t        |t        j                  «      s|S |j                  D ]ž  }t        |t        j                  «      sŒt        |j
                  j                  t        «      sŒC|j
                  j                  sŒZt        |j
                  j                  |rdnd¬«      }|j                  | j                  |«      «       Œ  |S )z©Build content item(s) from the model response. When the request supplied
        grounding, the response is qualified ``guard_content`` so Bedrock can score it.
        Úguard_contentN©rf   rg   )r‡   ÚlitellmrC   Úchoicesr?   rÉ   rI   rl   re   rÌ   rÖ   )r®   rz   rÔ   r¾   ÚchoicerÐ   s         rp   rÙ   z.BedrockGuardrail._build_response_content_itemso  s    € ð 24ˆÜ˜(¤G×$9Ñ$9Ô:ØˆLØ×&Ñ&ò 
	>ˆFä˜6¤7§?¡?Õ3Ü˜vŸ~™~×5Ñ5´sÕ;Ø—N‘N×*Ó*ä*ØŸ™×/Ñ/Ù1>™oÀDô�ð —‘˜T×5Ñ5°eÓ<Õ=ð
	>ð ˆro   rJ   )rÆ   rÓ   c                 ó€   — t        |¬«      }|dk(  r| j                  |¬«      }|S |dk(  r| j                  ||¬«      }|S )a  
        Convert the litellm messages/response to the bedrock request format.

        If source is "INPUT", then messages is required.
        If source is "OUTPUT", then response is required.

        Returns:
            BedrockRequest: The bedrock request object.
        rÇ   rÆ   ©rÄ   rÓ   )rz   rÄ   )r6   rÑ   rÛ   )r®   rJ   rÄ   rz   rÍ   s        rp   Úconvert_to_bedrock_formatz*BedrockGuardrail.convert_to_bedrock_format…  sY   € ô +9ÀÔ*GˆØ�WÒØ"×HÑHÐRZÐHÓ[ˆOð Ðð �xÒØ"×IÑIÐS[ÐfnÐIÓoˆOØÐro   rÉ   c                 óÈ  — |j                  d«      }|€yg }t        |t        «      r|j                  t	        |d¬«      «       |S t        |t
        «      r�|D ]ˆ  }t        |t        «      rId|v rEt        j                  |j                  dd«      «      }|j                  t	        |d   |¬«      «       Œ\t        |t        «      sŒm|j                  t	        |d¬«      «       ŒŠ |S )a'  
        Flatten a message into text blocks, preserving any contextual-grounding
        qualifier carried by the content-block ``type`` (grounding_source / query).
        Untagged text keeps ``qualifier=None`` so the payload is unchanged for
        callers that do not use grounding.
        rI   NrÞ   rf   ÚtypeÚ )r¢   r‡   rl   rÌ   re   rv   rˆ   r`   )r®   rÉ   rI   rÏ   Úitemrg   s         rp   rË   z.BedrockGuardrail.get_content_items_for_message›  sË   € ð !Ÿ™ YÓ/ˆØˆ?ØØ24ˆÜ�gœsÔ#Ø�M‰MÔ,°'ÀTÔJÔKð ˆô ˜¤Ô&Øò Q�Ü˜d¤DÔ)¨f¸©nÜ :× >Ñ >¸t¿x¹xÈÐPRÓ?SÓ T�IØ—M‘MÔ"4¸$¸v¹,ÐR[Ô"\Õ]Ü ¤cÕ*Ø—M‘MÔ"4¸$È$Ô"OÕPðQð ˆro   rÐ   c                 ó~   — t        |j                  ¬«      }|j                  �|j                  g|d<   t        |¬«      S )zEBuild a Bedrock content item, attaching qualifiers only when present.rÊ   Ú
qualifiers)r7   rf   rg   r0   )r®   rÐ   Útext_contents      rp   rÖ   z$BedrockGuardrail._build_content_item±  s6   € ä0°e·j±jÔAˆØ�?‰?Ð&Ø*/¯/©/Ð):ˆL˜Ñ&Ü! |Ô4Ð4ro   c                 óê   — g }|xs g D ]g  }|j                  d«      }| j                  |¬«      xs g D ];  }|j                  dk(  s|j                  dk(  sŒ"|t        v sŒ+|j	                  |«       Œ= Œi |S )a0  Harvest grounding_source/query blocks from the request for an OUTPUT scan.

        ``grounding_source`` is honored only from app-authored roles (system /
        developer). A grounding_source tag on a ``user``, ``tool`` or ``function``
        message is ignored, so neither a forwarded end-user message nor a tool/function
        result carrying externally-influenced content can supply fake evidence for the
        contextual-grounding check to grade the response against. ``query`` is accepted
        from any role (it is the user's question).
        ÚrolerÈ   r_   r^   )r¢   rË   rg   rc   rÌ   )r®   rÄ   Ú	groundingrÉ   rí   rÐ   s         rp   rÕ   z*BedrockGuardrail._collect_grounding_blocks¸  s…   € ð 68ˆ	Ø’~ 2ò 	,ˆGØ—;‘;˜vÓ&ˆDØ×;Ñ;ÀGÐ;ÓLÒRÐPRò ,�à—O‘O wÒ.Ø—‘Ð*<Ó<ØÔ ?Ò?à×$Ñ$ UÕ+ñ,ð	,ð Ðro   c                 ó   — | j                   duS )NT)r›   )r®   s    rp   Úsupports_scan_only_tool_resultsz0BedrockGuardrail.supports_scan_only_tool_resultsÎ  s   € Ø×=Ñ=ÀTÐIÐIro   c                 óÚ   — |€t        ddd«      S | j                  durt        |dd«      S | j                  |d¬«      }|€t        ddd«      S t        |«      }||   g}t        |||g¬«      S )z<Return payload + merge metadata for the latest user message.NTÚuser©Útarget_role)rs   rt   ru   )rr   r›   Ú_find_latest_message_indexrv   )r®   rÄ   Úlatest_indexrt   rs   s        rp   Ú$_prepare_guardrail_messages_for_rolez5BedrockGuardrail._prepare_guardrail_messages_for_roleÑ  s‘   € ð ÐÜ/°°d¸DÓAÐAà×9Ñ9ÀÑEÜ/°¸$ÀÓEÐEà"×=Ñ=¸hÐTZÐ=Ó[ˆØÐÜ/°°d¸DÓAÐAä#'¨£>ÐØ#+¨LÑ#9Ð":ÐÜ+Ø-Ø/Ø(˜>ô
ð 	
ro   rô   c                 óx   — t        t        |«      dz
  dd«      D ]  }||   j                  dd «      |k(  sŒ|c S  y )Né   éÿÿÿÿrí   )Úranger×   r¢   )r®   rÄ   rô   Úindexs       rp   rõ   z+BedrockGuardrail._find_latest_message_indexê  sF   € Üœ3˜x›=¨1Ñ,¨b°"Ó5ò 	ˆEØ˜‰×"Ñ" 6¨4Ó0°KÓ?Ø’ð	ð ro   c                 óŒ   — | j                  d«      }t        |t        «      ryt        |t        «      rt	        d„ |D «       «      S y)zPCount the text segments the guardrail translation layer extracts from a message.rI   rù   c              3   óf   K  — | ])  }t        |t        «      sŒ|j                  d «      €Œ&d–— Œ+ y­w)rf   Nrù   ©r‡   rˆ   r¢   ©Ú.0rè   s     rp   ú	<genexpr>z8BedrockGuardrail._count_message_texts.<locals>.<genexpr>÷  s(   è ø€ Òh˜T´
¸4ÄÕ0FÈ4Ï8É8ÐTZÓK[ÑKg”qÑhùs   ‚1˜1ª1r   )r¢   r‡   rl   rv   Úsum)rÉ   rI   s     rp   Ú_count_message_textsz%BedrockGuardrail._count_message_textsð  s=   € ð !Ÿ™ YÓ/ˆÜ�gœsÔ#ØÜ�gœtÔ$ÜÑh WÔhÓhÐhØro   Ústructured_messagesÚtarget_indexÚtextsc                 ó´   — d}d}d}t        |«      D ]-  \  }}| j                  |«      }	||k  r||	z  }n||k(  r|	}||	z  }Œ/ |t        |«      k7  s|dk(  ry||fS )a&  
        Map one message's text segments to their (offset, length) slice in the
        flat `texts` list built by the guardrail translation handler.

        Returns None when the reconstruction does not line up with `texts`
        (the caller must then avoid positional write-back).
        r   N)Ú	enumerater  r×   )
r®   r  r  r  ÚoffsetÚtotalÚtarget_countrü   rÉ   Úcounts
             rp   Ú_locate_message_texts_slicez,BedrockGuardrail._locate_message_texts_sliceú  s†   € ð ˆØˆØˆÜ'Ð(;Ó<ò 	‰NˆE�7Ø×-Ñ-¨gÓ6ˆEØ�|Ò#Ø˜%‘‘Ø˜,Ò&Ø$�Ø�U‰N‰Eð	ð ”C˜“JÒ ,°!Ò"3ØØ�|Ð#Ð#ro   Úinputsr8   Úrequest_dataÚ
input_type)Úrequestrz   c                 óÈ  — |D �cg c]  }t        d|¬«      ‘Œ }}| j                  durt        |dd¬«      S t        t        t
           dz  |j                  d«      xs |j                  d«      «      }|d	k7  s|s.| j                  |¬
«      }t        |j                  xs |dd¬«      S | j                  |d¬«      }	|	€Dt        | «      rt        j                  d«       t        j                  d«       t        dddd¬«      S ||	   }
| j                  |
«      dk(  r$t        j                  d«       t        dddd¬«      S t        |
g| j                  ||	|¬«      d¬«      S c c}w )aù  
        Decide which messages an apply_guardrail scan should cover.

        With ``experimental_use_latest_role_message_only`` enabled, request
        scans must select by the ORIGINAL message roles. The flat `texts` list
        has no role information, and wrapping it in role="user" mock messages
        makes the latest-user filter degenerate to "latest text of any role",
        leaking tool/assistant content to the INPUT scan
        (https://github.com/BerriAI/litellm/issues/23476).
        rò   ©rí   rI   TNF)r   r€   r�   r  rÄ   r  rã   ró   z¢Bedrock Guardrail: experimental_use_latest_role_message_only scans only the latest user message, so scan_only_tool_results leaves nothing to scan for this requestzGBedrock Guardrail: no user-role message in request, skipping INPUT scan)r‚   r   zOBedrock Guardrail: latest user message has no text content, skipping INPUT scan)r  r  r  )r-   r›   r~   r   rv   r,   r¢   r÷   rs   rõ   r   r   r«   r¬   r  r  )r®   r  r  r  r  rf   Úmock_messagesr  Úfilter_resultÚlatest_user_indexÚselected_messages              rp   Ú$_select_messages_for_apply_guardrailz5BedrockGuardrail._select_messages_for_apply_guardrail  s¡  € ð" sxÖ0xÐjnÔ1JÐPVÐ`dÖ1eÐ0xˆÐ0xà×9Ñ9ÀÑEÜ1Ø"/Ø"Ø$)ôð ô  &*ÜÔ!Ñ" TÑ)Ø�J‰JÐ,Ó-ÒM°×1AÑ1AÀ*Ó1Mó&
Ðð ˜Ò"Ñ*=ð $(×#LÑ#LÐVcÐ#LÓ#dˆMÜ1Ø"/×"@Ñ"@Ò"QÀMØ"Ø$)ôð ð $(×#BÑ#BÐCVÐdjÐ#BÓ#kÐØÐ$Ü=¸dÔCÜ$×,Ñ,ðfôô !×&Ñ&Ð'pÔqÜ1°$¸¸dÈdÔSÐSà"5Ð6GÑ"HÐØ×$Ñ$Ð%5Ó6¸!Ò;Ü ×&Ñ&Øaôô 2°$¸¸dÈdÔSÐSä-Ø/Ð0Ø×:Ñ:Ø$7Ø.Øð ;ó ð
 !%ô
ð 	
ùòg 1ys   …EÚmasked_textsr€   r�   c                 ó¤   — |s|S |�0|\  }}t        |«      }t        |d| «      D ]  \  }}	|	|||z   <   Œ |S |rt        j                  d«       |S |S )u!  
        Reconcile the guardrail's masked output with the flat `texts` list.

        - No masked output: keep the originals (guardrail allowed content as-is).
        - A slice was scanned: write masked content back to those positions only,
          keeping the list aligned with the caller's messageâ†”text mappings.
        - A role-selected subset was scanned but could not be mapped back to
          flat-text positions (scanned_slice is None): keep the originals rather
          than misapply masked content to the wrong message. Guarding on
          scanned_slice rather than a length comparison also covers the case
          where the masked subset happens to match len(texts) (e.g. both length
          1).
        - Otherwise (whole list scanned): use the masked output as-is.
        Nz_Bedrock Guardrail: could not align masked texts with request texts, skipping masking write-back)rv   r	  r   r«   )
r®   r  r  r€   r�   r
  ÚlengthÚmerged_textsÚmasked_indexÚmasked_texts
             rp   Ú_merge_masked_textsz$BedrockGuardrail._merge_masked_textsc  s|   € ñ* ØˆLØÐ$Ø*‰NˆF�FÜ"& u£+ˆLÜ-6°|ÀGÀVÐ7LÓ-Mò BÑ)�˜kØ6A�˜V lÑ2Ò3ðBàÐÙÜ ×(Ñ(Øqôð ˆLØÐro   rt   Úupdated_target_messagesru   c                 ó–   — |s|S |sg }t        |«      }|st        |«      }t        ||«      D ]  \  }}|t        |«      k  sŒ|||<   Œ |S r²   )rv   Úzipr×   )r®   rt   r!  ru   Úmerged_messagesÚreplacement_indexÚupdated_messages          rp   Ú_merge_filtered_messagesz)BedrockGuardrail._merge_filtered_messages‡  sn   € ñ Ø*Ð*á Ø "ÐäÐ0Ó1ˆÙÜ"Ð#:Ó;ˆOÜ25°nÐF]Ó2^ò 	EÑ.Ð˜Ø ¤3 Ó#7Ó7Ø5D�Ð 1Ò2ð	Eð Ðro   c                 óÒ  — 	 ddl m} | j                  j	                  dd «      }| j                  j	                  dd «      }| j                  j	                  dd «      }| j                  j	                  dd «      }| j                  j	                  dd «      }| j                  j	                  d	d «      }| j                  j	                  d
d «      }| j                  j	                  dd «      }	| j                  j	                  dd «      }
| j                  j	                  dd «      }| j                  |¬«      }| j                  ||||||||	|
|¬«
      }||fS # t        $ r t        d«      ‚w xY w)Nr   r:   ú7Missing boto3 to call bedrock. Run 'pip install boto3'.Úaws_secret_access_keyÚaws_access_key_idÚaws_session_tokenÚaws_region_nameÚaws_role_nameÚaws_session_nameÚaws_profile_nameÚaws_web_identity_tokenÚaws_sts_endpointÚaws_external_id©r-  )
r+  r*  r,  r-  r/  r0  r.  r1  r2  r3  )Úbotocore.credentialsr;   ÚImportErrorr¤   r¢   Ú)get_aws_region_name_for_non_llm_api_callsÚget_credentials)r®   r;   r*  r+  r,  r-  r.  r/  r0  r1  r2  r3  Úcredentialss                rp   Ú_load_credentialsz"BedrockGuardrail._load_credentials   s�  € ð	YÝ8ð (,×';Ñ';×'?Ñ'?Ð@WÐY]Ó'^ÐØ#'×#7Ñ#7×#;Ñ#;Ð<OÐQUÓ#VÐØ#'×#7Ñ#7×#;Ñ#;Ð<OÐQUÓ#VÐØ×.Ñ.×2Ñ2Ð3DÀdÓKˆØ#×3Ñ3×7Ñ7¸ÈÓNˆØ"&×"6Ñ"6×":Ñ":Ð;MÈtÓ"TÐØ"&×"6Ñ"6×":Ñ":Ð;MÈtÓ"TÐØ(,×(<Ñ(<×(@Ñ(@ÐAYÐ[_Ó(`ÐØ"&×"6Ñ"6×":Ñ":Ð;MÈtÓ"TÐØ!%×!5Ñ!5×!9Ñ!9Ð:KÈTÓ!Rˆð ×HÑHØ+ð Ió 
ˆð +/×*>Ñ*>Ø/Ø"7Ø/Ø+Ø-Ø-Ø'Ø#9Ø-Ø+ð +?ó +
ˆð ˜OÐ+Ð+øô? ò 	YÜÐWÓXÐXð	Yús   ‚E ÅE&Údatar¤   r-  Úapi_keyÚextra_headersÚrequest_pathc                 óŠ  — ddi}|�ddi|¥}| j                   j                  dd «      }	| j                  d |	|¬«      \  }
}|€d| j                  › d| j                  › d�}|› |› �}t        j                  |«      j                  d«      }|�|}nt        d	«      }|r	 d
dl	m
} d|› �|d<    |d|||¬«      }nL	 d
dlm} d
dl	m
}  ||d|«      } |d|||¬«      }|j                  |«       |�d|v r|d   |j                  d<   |j!                  «       }|S # t        $ r t        d«      ‚w xY w# t        $ r t        d«      ‚w xY w)NzContent-Typezapplication/jsonÚaws_bedrock_runtime_endpoint)Úapi_baser@  r-  z/guardrail/z	/version/z/applyúutf-8ÚAWS_BEARER_TOKEN_BEDROCKr   )Ú
AWSRequestr)  zBearer ÚAuthorizationÚPOST)ÚmethodÚurlr;  Úheaders)Ú	SigV4AuthrG   )r¤   r¢   Úget_runtime_endpointr‘   r’   ÚjsonÚdumpsÚencoder)   Úbotocore.awsrequestrD  r6  Úbotocore.authrJ  Úadd_authrI  Úprepare)r®   r9  r;  r¤   r-  r<  r=  r>  rI  r@  Ú_Úproxy_endpoint_urlÚencoded_dataÚaws_bearer_tokenrD  r  rJ  Úsigv4Úprepped_requests                      rp   Ú_prepare_requestz!BedrockGuardrail._prepare_requestÆ  s¸  € ð "Ð#5Ð6ˆØÐ$Ø%Ð'9ÐK¸]ÐKˆGà.2×.BÑ.B×.FÑ.FÐGeÐgkÓ.lÐ$Ø $× 9Ñ 9ØØ)EØ+ð !:ó !
ÑˆÐð ÐØ(¨×)AÑ)AÐ(BÀ)ÈD×LaÑLaÐKbÐbhÐiˆLØ 2Ð3°L°>ÐBÐÜ"Ÿj™j¨Ó.×5Ñ5°gÓ>ˆð ÐØ+2Ñä-Ð.HÓIÐáð]Ý:ð *1Ð1AÐ0BÐ'CˆG�OÑ$Ù ØØ&Ø!Øô	‰Gð]Ý3Ý:ñ % [°)¸_ÓMˆEÙ ØØ&Ø!Øô	ˆGð �N‰N˜7Ô#àÐ)¨oÀÑ.Nà3@ÀÑ3Q�—‘ Ñ0Ø!(§¡Ó!2ˆàÐøô= ò ]Ü!Ð"[Ó\Ð\ð]ûô ò ]Ü!Ð"[Ó\Ð\ð]ús   ÂD Â8D- ÄD*Ä-EÚlogging_event_typec              ƒ   ó¢   K  — | j                   �| j                  |||||¬«      ƒ d{  –—† S | j                  |||||¬«      ƒ d{  –—† S 7 Œ"7 Œ­w)az  Dispatch to the configured Bedrock guardrail API.

        ``checks`` selects the resource-less, detect-only InvokeGuardrailChecks API;
        otherwise the ApplyGuardrail API is used. Both return a ``BedrockGuardrailResponse``
        (the checks path returns an empty one on a pass, which downstream masking treats
        as a no-op) and raise on a blocked request.
        N)rJ   rÄ   rz   r  rZ  )r”   Ú%_make_invoke_guardrail_checks_requestÚ_make_apply_guardrail_request)r®   rJ   rÄ   rz   r  rZ  s         rp   Úmake_bedrock_api_requestz)BedrockGuardrail.make_bedrock_api_request  sx   è ø€ ð �;‰;Ð"Ø×CÑCØØ!Ø!Ø)Ø#5ð Dó ÷ ð ð ×7Ñ7ØØØØ%Ø1ð 8ó 
÷ 
ð 	
ðøð
ús!   ‚&A¨A©AÁAÁAÁAc              ƒ   óÒ  K  — t        j                  t        j                  «      }t	        | j                  |||¬«      «      }d}|rc| j                  |¬«      }	|j                  |	j                  «       D �
�ci c]  \  }
}|
t        vr|
|“Œ c}}
«       |j                  d«      �|d   }|�|n$|dk(  rt        j                  nt        j                  }t        |j                  d«      xs d«      }|s+t        j                   d| j"                  |«       t%        «       S | j'                  «       \  }}| j)                  |«       }g }	 | j+                  ||||||||||¬	«
      ƒ d{  –—† }| j5                  |«      }| j7                  |||||¬«       |S c c}}
w 7 Œ3# t,        $ rA}t/        |j0                  t        «      s!| j3                  |j0                  |||||¬
«       ‚ d}~ww xY w­w)aß  Scan `messages`/`response` with ApplyGuardrail, chunking if it is too large.

        Content is bin-packed into budget-sized batches and each batch posted
        sequentially, every batch independently falling back to bisection if AWS
        rejects it. The per-batch responses are merged so callers cannot tell whether
        chunking happened.

        Content using contextual grounding opts out of chunking entirely: grounding is
        scored holistically against the whole reference source, so bisecting it would
        fragment that evaluation and yield misleading scores. Such a request keeps the
        old behavior of surfacing a too-large error rather than being split.

        `logging_event_type` drives what UI and spend logs report. It is distinct from
        Bedrock's `source`, which is INPUT vs OUTPUT for the API body and must not be
        confused with the proxy hook (pre_call / during_call / post_call); when omitted,
        the legacy source-derived mapping is kept for backward compatibility.

        A guardrail *block* is logged where it happens, in
        `_post_apply_guardrail_content`, because chunking stops immediately and there is
        no later merged response to log instead. Everything else that fails out of the
        chunking flow (an unrecoverable too-large error, a non-size validation error,
        exhausted throttle retries) is a genuine end-to-end failure of this one logical
        guardrail call and is logged exactly once here.
        ©rJ   rÄ   rz   N©r  r<  rÆ   rI   rn   zDBedrock Guardrail %s: no %s content to scan, skipping ApplyGuardrail©
rI   Úbase_request_datar9  r-  r<  r  Ú
event_typeÚ
start_timeÚallow_chunkingÚcompleted_chunk_usages)Údetailr  rd  re  r-  rg  )Úmerged_responser  rd  re  r-  )r   Únowr   Úutcrˆ   rä   Ú)get_guardrail_dynamic_request_body_paramsÚupdater¾   rK   r¢   r+   r³   r´   r|   r   r¬   Úguardrail_namer4   r:  Ú"_content_uses_contextual_groundingÚ&_apply_guardrail_content_with_chunkingr   r‡   rh  Ú_log_apply_guardrail_failureÚ"_merge_bedrock_guardrail_responsesÚ_log_apply_guardrail_success)r®   rJ   rÄ   rz   r  rZ  re  Úbedrock_request_datar<  Údynamic_request_body_paramsrÁ   rÂ   rd  rI   r9  r-  rf  rg  Ú	responsesÚexcri  s                        rp   r]  z.BedrockGuardrail._make_apply_guardrail_request*  s/  è ø€ ô@ %ŸL™L¬¯©Ó6ˆ
Ü,0Ø×*Ñ*°&À8ÐV^Ð*Ó_ó-
Ðð #ˆÙØ*.×*XÑ*XÐfrÐ*XÓ*sÐ'Ø ×'Ñ'ð 'B×&GÑ&GÓ&I÷á"˜˜UØÔ"@Ñ@ð ˜‘Jóôð ×Ñ 	Ó*Ð6Ø& yÑ1�ð "Ð-ñ à28¸GÒ2CÔ%×.Ò.ÔI\×IfÑIfð 	ô :?Ð?S×?WÑ?WÐXaÓ?bÒ?hÐfhÓ9iˆÙô !×&Ñ&ØVØ×#Ñ#Øôô
 ,Ó-Ð-Ø'+×'=Ñ'=Ó'?Ñ$ˆ�_Ø$(×$KÑ$KÈGÓ$TÐ TˆàEGÐð	Ø%)×%PÑ%PØØ"6Ø'Ø /ØØ)Ø%Ø%Ø-Ø'=ð &Qó &÷  ˆIð. "&×!HÑ!HÈÓ!SˆØ×)Ñ)Ø+Ø%Ø!Ø!Ø+ð 	*ô 	
ð Ðùó{ð< ùô ò 
	Ü˜cŸj™j¬$Ô/Ø×1Ñ1ØŸ:™:Ø!-Ø)Ø)Ø$3Ø+Að 2ô ð ûð
	üsI   ‚A5G'Á7F
ÂB9G'ÅF Å$FÅ%F Å)/G'ÆF Æ	G$Æ#<GÇG$Ç$G'rI   rc  r9  r;   rd  re  r   rf  rg  .c              ƒ   óú  ‡K  — 	 | j                  |||||||||
¬«	      ƒ d{  –—† }t        |t        |«      d¬«      fS 7 Œ# t        $ �r­}|	�r¤| j	                  |j
                  «      �rˆ| j                  || j                  ¬«      }t        |«      dkD  r‚t        j                  dt        |«      t        |«      | j                  «       |D �cg c]&  }| j                  |||||||||	|
¬«
      ƒ d{  –—†7  ‘Œ( nc c}w }}t        d„ |D «       «      cY d}~S | j                  |«      }|€‚ |\  }}t        |«      dk(  }t        j                  d	t        |«      t        |«      t        |«      «       | j                  |||||||||	|
¬«
      ƒ d{  –—†7  }| j                  |||||||||	|
¬«
      ƒ d{  –—†7  }t        |«      t        |«      z   Š|rt        ˆfd
„‰D «       «      cY d}~S ‰cY d}~S ‚ d}~ww xY w­w)aQ	  Post `content` to ApplyGuardrail, chunking only if AWS rejects it as too large.

        Tries `content` as a single call first. AWS's per-request "maximum input
        size in text units" quota is account/region/policy-dependent and cannot be
        predicted ahead of time, so it is only ever discovered reactively: on an
        error whose message indicates the input was too large (a ThrottlingException
        in practice, a ValidationException per the docs -- see
        ``_is_input_too_large_error``), the content is re-sent in smaller pieces.

        Probing with the whole payload first is what keeps a request AWS would have
        accepted at exactly one call. Packing into fixed batches up front instead
        would split conversations AWS was happy to take whole, multiplying billed
        calls and guardrail latency on traffic that never had a size problem, and
        no fixed budget can avoid that because the real cap is unknown here.

        Once a rejection proves the payload is over the cap, a multi-item payload is
        re-sent as ``chunk_budget_chars``-sized batches rather than bisected: that
        reaches a working size in one step instead of paying an O(log n) ladder of
        rejected calls. Bisection remains the fallback for anything bin-packing
        cannot make smaller, which is what makes the recursion terminate: a batch
        already inside the budget packs back to itself, so it falls through to the
        split below. A single oversized
        content item (one very long message) is split by its own text instead of
        by list length, since a list of length 1 has no items left to bisect --
        the resulting fragments all carry a ``fragment_group_size`` so the merge
        step can recombine them into the one content item they came from, rather
        than treating each fragment as its own item when reconstructing positions
        for masking. That count covers however many fragments the item ended up
        split into, not just two, since it can be bisected repeatedly: the
        outermost single-item split stamps the total leaf count on every leaf
        below it, overwriting any smaller count an inner split had set. A real
        guardrail block on any (sub-)chunk raises immediately
        -- callers must not lose that signal by continuing to post the remaining
        chunks.
        ©	rI   rc  r9  r-  r<  r  rd  re  rg  Nrù   )rz   rI   r{   )Úbudgetz}Bedrock Guardrail: ApplyGuardrail rejected %d content item(s) as too large; re-sending as %d batches of at most %d charactersrb  c              3   ó.   K  — | ]  }|D ]  }|–— Œ Œ y ­wr²   rn   )r  ÚresultsÚresults      rp   r  zJBedrockGuardrail._apply_guardrail_content_with_chunking.<locals>.<genexpr>î  s   è ø€ Ò [¨GÐSZÒ [È¤Ð [ Ñ [ùó   ‚ztBedrock Guardrail: ApplyGuardrail rejected %d content item(s) as too large; splitting into %d + %d and retrying eachc              3   óT   •K  — | ]  }|j                  t        ‰«      ¬ «      –— Œ! y­w))r{   N)Ú_replacer×   )r  r}  Úcombined_resultss     €rp   r  zJBedrockGuardrail._apply_guardrail_content_with_chunking.<locals>.<genexpr>  s'   øè ø€ ò !ØW]˜Ÿ™¼CÐ@PÓ<Q˜×Rñ!ùs   ƒ%()Ú(_post_apply_guardrail_content_with_retryry   r|   r   Ú_is_input_too_large_errorrh  Ú_bin_pack_bedrock_contentr˜   r×   r   r«   rp  Ú_split_bedrock_content)r®   rI   rc  r9  r-  r<  r  rd  re  rf  rg  rz   rw  ÚbatchesÚbatchÚbatch_resultsÚsplit_contentÚ
first_halfÚsecond_halfÚis_single_item_text_splitÚfirst_resultsÚsecond_resultsr�  s                         @rp   rp  z7BedrockGuardrail._apply_guardrail_content_with_chunking‘  sq  øè ø€ ð`X	Ø$(×$QÑ$QØØ"3Ø'Ø /ØØ)Ø%Ø%Ø'=ð %Ró 
%÷ 
ˆHô *Ø%Ü! '›NØ()ôðð ð
ùô$ ó E	Ú $×"@Ñ"@ÀÇÁÕ"LØ!%×!?Ñ!?ÀÐPT×PgÑPgÐ!?Ó!h�Ü�w“< !Ò#Ü(×0Ñ0ðLä˜G›Ü˜G›Ø×/Ñ/ôð( &-ö,ð "ð #×IÑIØ$)Ø.?Ø(3Ø,;Ø$+Ø)5Ø'1Ø'1Ø+9Ø3Ið Jó ÷ ò ñ,ùò ,�Mð ,ô !Ñ [°}Ô [Ó[Õ[Ø'+×'BÑ'BÀ7Ó'K�Ø Ð(ØØ*7Ñ'�
˜KÜ36°w³<À1Ñ3DÐ)Ü$×,Ñ,ð?ä˜“LÜ˜
“OÜ˜Ó$ôð .2×-XÑ-XØ&Ø&7Ø +Ø$3Ø#Ø!-Ø)Ø)Ø#1Ø+Að .Yó .÷ (ð (�ð /3×.YÑ.YØ'Ø&7Ø +Ø$3Ø#Ø!-Ø)Ø)Ø#1Ø+Að /Zó /÷ )ð )�ô +0°Ó*>ÄÀ~ÓAVÑ*VÐ Ù,Ü ó !Øaqô!ó õ ð (Õ'ØûðKE	üs�   ƒG;…A ¢?£A ¾G;¿A Á
G8ÁBG3Ã#C9Ã0C3Ã1C9Ã8G3ÄG8ÄG;ÄA8G3ÆFÆ#G3Æ3F6Æ41G3Ç%G8Ç&G;Ç+G3Ç,G8Ç-G;Ç2G3Ç3G8Ç8G;c
              ƒ   ó‚  K  — t        t        dz   «      D ]&  }
	 | j                  |||||||||	¬«	      ƒ d{  –—† c S  t        dd¬«      ‚7 Œ# t        $ rf}|j                  dk7  s$| j                  |j                  «      s	|
t        k\  r‚ t        j                  t        d|
z  z  «      ƒ d{  –—†7   Y d}~Œ¢d}~ww xY w­w)	a˜  Post one ApplyGuardrail call for `content`, retrying with exponential
        backoff on AWS ThrottlingException (HTTP 429).

        Chunking already trades one oversized call for several smaller ones, so
        retries here are capped low -- they must not multiply per-request latency
        by an order of magnitude when the account's per-second text-unit quota is
        the binding constraint rather than the per-request size quota.

        A too-large rejection is deliberately excluded from the retry. AWS reports
        it as a ThrottlingException (429), not only as a ValidationException, but
        unlike a genuine throttle it is not transient: re-posting the same
        oversized content can never succeed. Retrying it would burn every backoff
        sleep and every (billed) attempt before the caller's bisection gets a
        chance to split the content, at every level of the recursion.
        rù   ry  Ni­  é   éô  z,Bedrock guardrail throttle retries exhausted©Ústatus_coderh  )
rû   rN   Ú_post_apply_guardrail_contentr   r“  rƒ  rh  ÚasyncioÚsleeprP   )r®   rI   rc  r9  r-  r<  r  rd  re  rg  Úattemptrw  s               rp   r‚  z9BedrockGuardrail._post_apply_guardrail_content_with_retry  sÔ   è ø€ ô6 ÔJÈQÑNÓOò 	bˆGðbØ!×?Ñ?Ø#Ø&7Ø +Ø$3Ø#Ø!-Ø)Ø)Ø+Að @ó 
÷ 
ò 
ð	bô* ¨Ð4bÔcÐcð'
ùô !ò bà—O‘O sÒ*Ø×5Ñ5°c·j±jÔAØÔ"OÒOàÜ—m‘mÔ$QÐUVÐX_ÑU_Ñ$`Óa×aÖaûðbüsJ   ‚B?™A¶A·AºB?ÁAÁ	B<ÁAB7Â,B/Â-B7Â2B?Â7B<Â<B?c
           	   ƒ   óþ  K  — i |¥d|i¥}
| j                  ||
| j                  ||¬«      }t        j                  d|
|j                  |j
                  «       | j                  ||||d¬«      ƒ d{  –—† }|j                  dk(  rª|j                  «       }t        j                  dt        |«      «       t        di |¤Ž}| j                  |«      r+| j                  |||||||	¬	«       | j                  ||¬
«      ‚|j                  d«      }t        |t         «      r|	j#                  |«       |S | j%                  |«      \  }}t        j&                  d|j                  |j(                  «       t+        ||¬«      ‚7 �Œ
­w)aÿ  Make exactly one signed ApplyGuardrail HTTP call for `content` and
        parse the result. Raises HTTPException on a guardrail block or any
        non-200 response (including 429, handled by the retry wrapper above).

        AWS also reports some failures inside a 200 body, tagging ``Output.__type``
        with an Exception marker. Those deliberately do NOT raise: the request proceeds,
        matching the behaviour of this code before chunking existed. The marker survives
        the merge, so the one consolidated log entry still records
        ``guardrail_failed_to_respond`` rather than a success. Making that path fail
        closed is a separate change, tracked apart from this PR, and belongs behind the
        existing ``unreachable_fallback`` setting rather than a hardcoded status.

        A block is logged here rather than by the caller: it ends the whole chunking
        flow immediately, with no further chunks attempted, so there is no later
        merged response for the caller to log instead. The logged usage still spans
        the whole logical request: chunks that passed before the block appended what
        AWS billed them to ``completed_chunk_usages``, and the attempt log sums those
        with the blocking call's own usage.
        rI   )r9  r;  r¤   r-  r<  z0Bedrock AI request body: %s, url %s, headers: %sF)Úprepared_requestr  rd  re  Úlog_transport_failureNéÈ   zBedrock AI response : %s)Úhttpx_responseÚjson_responser  rd  re  r-  rg  ra  Úusagez<Bedrock AI: error in response. Status code: %s, response: %sr’  rn   )rY  r¤   r   r¬   rH  rI  Ú_sign_and_postr“  rL  r   r4   Ú)_should_raise_guardrail_blocked_exceptionÚ_log_apply_guardrail_attemptÚ)_get_http_exception_for_blocked_guardrailr¢   r‡   rˆ   rÌ   Ú'_parse_bedrock_guardrail_error_responseÚerrorrf   r   )r®   rI   rc  r9  r-  r<  r  rd  re  rg  rt  r™  rœ  Ú_json_responseÚbedrock_guardrail_responseÚresponse_usager“  Údetail_messages                     rp   r”  z.BedrockGuardrail._post_apply_guardrail_contentM  sÂ  è ø€ ð>'
Øð'
à�wñ'
Ðð #'×"7Ñ"7Ø#Ø%Ø ×0Ñ0Ø+Øð #8ó #
Ðô 	×"Ñ"Ø>Ø Ø× Ñ Ø×$Ñ$ô		
ð '+×&9Ñ&9Ø-Ø%Ø!Ø!Ø"'ð ':ó '
÷ !
ˆð ×%Ñ%¨Ò,Ø$2×$7Ñ$7Ó$9ˆNä ×&Ñ&Ø*Ü2°>ÓBôô *BÑ)SÀNÑ)SÐ&Ø×=Ñ=Ð>XÔYØ×1Ñ1Ø#1Ø"0Ø!-Ø)Ø)Ø$3Ø+Að 2ô ð ×DÑDØ.¸\ð Eó ð ð %?×$BÑ$BÀ7Ó$KˆNÜ˜.¬$Ô/Ø&×-Ñ-Ø"ôð .Ð-à&*×&RÑ&RÐSaÓ&bÑ#ˆ�^Ü×"Ñ"ØJØ×&Ñ&Ø×Ñô	
ô
 ¨¸NÔKÐKðU!
ûs   ‚A.E=Á0E:Á1D
E=rœ  r�  c                 ó,  — |j                  d«      }t        |«      t        |t        «      r|fndz   }	|ri |¥d| j	                  |	«      i¥n|}
| j                  t        di |
¤Ž|¬«      }| j                  | j                  |
|xs i | j                  |¬«      |j                  «       t        j                  t        j                  «      j                  «       t        j                  t        j                  «      |z
  j                  «       ||xs d¬«	       y)a1  Log the blocking ApplyGuardrail attempt, which ends the whole chunking
        flow immediately. Its status derives from its own response, but its usage
        (and so its cost) spans every billed call of the logical request: the
        chunks that passed before the block plus the blocking call itself.rž  rn   r4  ©rz   N©	r¡   Úguardrail_json_responser  Úguardrail_statusre  Úend_timeÚdurationrd  Útracing_detail)r¢   r|   r‡   rˆ   Ú_sum_usage_countersÚ_build_tracing_detailr4   Ú:add_standard_logging_guardrail_information_to_request_datar¡   Ú&_get_bedrock_guardrail_response_statusÚ	timestampr   rj  r   rk  Útotal_seconds)r®   rœ  r�  r  rd  re  r-  rg  Úblocking_usageÚbilled_usagesÚlogged_json_responser°  s               rp   r¡  z-BedrockGuardrail._log_apply_guardrail_attemptª  s  € ð !.× 1Ñ 1°'Ó :ˆÜBGÐH^ÓB_Ü!+¨N¼DÔ!Aˆ^ÑÀrñC
ˆñ &ð	Øðà˜×1Ñ1°-Ó@òð
 ð 	ð !%× :Ñ :Ü$Ñ<Ð';Ñ<Èoð !;ó !
ˆð 	×GÑGØ#×6Ñ6Ø$8Ø%Ò+¨Ø!×HÑHÐR`ÐHÓaØ!×+Ñ+Ó-Ü—\‘\¤(§,¡,Ó/×9Ñ9Ó;Ü—l‘l¤8§<¡<Ó0°:Ñ=×LÑLÓNØ!Ø)Ò1¨Tð 	Hõ 
	
ro   ri  c                 óÖ  — | j                  ||¬«      }| j                  | j                  t        |«      |xs i dt	        |j                  d«      xs i j                  dd«      «      v rdnd|j                  «       t        j                  t        j                  «      j                  «       t        j                  t        j                  «      |z
  j                  «       ||xs d¬	«	       y)
a*  Log one logical ApplyGuardrail call -- possibly several chunk calls
        under the hood -- using its final merged response, so a chunked
        request produces exactly one telemetry entry, the same as an
        unchunked one would.

        AWS can report a failure inside an HTTP 200 body by tagging
        ``Output.__type`` with an exception marker. That marker survives the merge,
        so the status is derived from the merged response rather than assumed to be
        a success, which is what the pre-chunking code reported for that shape.r4  Ú	ExceptionÚOutputÚ__typerç   Úguardrail_failed_to_respondÚsuccessNr«  )r²  r³  r¡   rˆ   rl   r¢   rµ  r   rj  r   rk  r¶  )r®   ri  r  rd  re  r-  r°  s          rp   rs  z-BedrockGuardrail._log_apply_guardrail_successÓ  sË   € ð" !%× :Ñ :¸?Ð\kÐ :Ó lˆØ×GÑGØ#×6Ñ6Ü$(¨Ó$9Ø%Ò+¨ð ¤# ×':Ñ':¸8Ó'DÒ'JÈ×&OÑ&OÐPXÐZ\Ó&]Ó"^Ñ^ñ .àà!×+Ñ+Ó-Ü—\‘\¤(§,¡,Ó/×9Ñ9Ó;Ü—l‘l¤8§<¡<Ó0°:Ñ=×LÑLÓNØ!Ø)Ò1¨Tð 	Hõ 	
ro   rh  c                 óØ  — |r| j                  |«      nd}dt        |«      i}|�i |¥d|i¥n|}	|�| j                  t        |¬«      |¬«      nd}
| j	                  | j
                  |	|xs i d|j                  «       t        j                  t        j                  «      j                  «       t        j                  t        j                  «      |z
  j                  «       ||
xs d¬«	       y)a`  Log one logical ApplyGuardrail call that failed end-to-end (an
        unrecoverable too-large error, a non-size validation error, or
        exhausted throttle retries) as a single failure, rather than logging
        every failed attempt chunking made along the way. Chunk calls AWS
        billed before the failure still carry their usage and cost.Nr¤  rž  )rž  r4  r¾  r«  )r±  rl   r²  r4   r³  r¡   rµ  r   rj  r   rk  r¶  )r®   rh  r  rd  re  r-  rg  Úbilled_usageÚerror_payloadr�  r°  s              rp   rq  z-BedrockGuardrail._log_apply_guardrail_failureõ  sò   € ñ Si˜d×6Ñ6Ð7MÔNÐnrˆØ '¬¨V«Ð5ˆð Ð'ð 5ˆ}Ð4˜g |Ò4àð 	ð Ð'ð ×&Ñ&Ô'?ÀlÔ'SÐetÐ&Ôuàð 	ð
 	×GÑGØ#×6Ñ6Ø$1Ø%Ò+¨Ø:Ø!×+Ñ+Ó-Ü—\‘\¤(§,¡,Ó/×9Ñ9Ó;Ü—l‘l¤8§<¡<Ó0°:Ñ=×LÑLÓNØ!Ø)Ò1¨Tð 	Hõ 
	
ro   c                 ó^   — | D ](  }|j                  d«      xs i j                  d«      sŒ( y y)zËTrue if any content item carries a contextual-grounding qualifier
        (``grounding_source``, ``query``, or the ``guard_content`` the response
        itself is tagged with once grounding is present).rf   rê   TF©r¢   )rI   rè   s     rp   ro  z3BedrockGuardrail._content_uses_contextual_grounding  s7   € ð
 ò 	ˆDØ—‘˜Ó Ò& B×+Ñ+¨LÕ9Ùð	ð ro   rz  c           	      ó:  ‡— | st        | «      fS t        d„ | D «       «      }dt         t        t        f   dt        dt         t        t        f   fˆfd„}d„ t        t        ||d¬«      «      d	d
 D «       }t        d„ t        t	        || «      d„ ¬«      D «       «      S )a»  Pack whole content items, in order, into batches whose combined text
        length stays within `budget`, in a single pass that carries the running
        total rather than re-summing the open batch per item.

        This is the fast-path half of the hybrid chunking strategy: bin-packing
        at a conservative fixed budget keeps the common case at O(n / budget)
        ApplyGuardrail calls instead of the O(log n) round trips pure reactive
        bisection pays on every oversized request. An item whose own text
        already exceeds `budget` is not split here -- it becomes its own
        (still oversized) batch and is sent as-is; if AWS rejects that batch as
        too large, `_apply_guardrail_content_with_chunking`'s existing
        recursive-bisection fallback takes over for that batch only.

        `budget` comes from the guardrail's ``chunk_budget_chars`` setting and
        defaults to 25,000, matching ApplyGuardrail's default quota of 25 text
        units (roughly 1,000 characters each) per second. Packing to that size and
        posting sequentially is what keeps chunking from tripping the rate quota
        and trading a size error for a throttle. Accounts with raised quotas can
        configure a larger budget to spend fewer calls.

        The budget is not a correctness dependency either way. AWS's effective cap
        varies by account, region, and policy, is not a fixed character count, and
        cannot be read from config, so any batch it still rejects falls back to
        bisection, which self-corrects however wrong the value was. An over-large
        budget therefore costs one extra probe-and-bisect round trip rather than
        failing the request.
        c              3   óŽ   K  — | ]=  }t        |j                  d «      xs
 t        «       j                  d «      xs d«      –— Œ? y­w)rf   rç   N)r×   r¢   r7   r   s     rp   r  z=BedrockGuardrail._bin_pack_bedrock_content.<locals>.<genexpr>H  s:   è ø€ ÒuÐeiœs D§H¡H¨VÓ$4Ò$LÔ8JÓ8L×#QÑ#QÐRXÓ#YÒ#_Ð]_×`Ñuùs   ‚AAÚcarriedr  r…   c                 ó:   •— | \  }}||z   ‰k  r|||z   fS |dz   |fS )Nrù   rn   )rÇ  r  Úbatch_indexÚusedrz  s       €rp   Úassignz:BedrockGuardrail._bin_pack_bedrock_content.<locals>.assignJ  s7   ø€ Ø 'ÑˆK˜Ø�f‰} Ò&Ø" D¨6¡MÐ1Ð1Ø ‘? FÐ*Ð*ro   c              3   ó&   K  — | ]	  \  }}|–— Œ y ­wr²   rn   )r  rü   rS  s      rp   r  z=BedrockGuardrail._bin_pack_bedrock_content.<locals>.<genexpr>P  s   è ø€ Òm©(¨%°¤Ñmùó   ‚)r   r   ©Úinitialrù   Nc              3   óF   K  — | ]  \  }}t        d „ |D «       «      –— Œ y­w)c              3   ó&   K  — | ]	  \  }}|–— Œ y ­wr²   rn   )r  rS  rè   s      rp   r  zGBedrockGuardrail._bin_pack_bedrock_content.<locals>.<genexpr>.<genexpr>R  s   è ø€ Ò,™7˜1˜d”$Ñ,ùrÍ  N©r|   )r  rS  Úgroups      rp   r  z=BedrockGuardrail._bin_pack_bedrock_content.<locals>.<genexpr>Q  s'   è ø€ ò 
á��5ô Ñ, eÔ,×,ñ
ùó   ‚!c                 ó   — | d   S )Nr   rn   )Úpairs    rp   ú<lambda>z<BedrockGuardrail._bin_pack_bedrock_content.<locals>.<lambda>S  s   € ÐRVÐWXÑRY€ ro   ©rÁ   )r|   rw   r   r	   r#  )rI   rz  ÚlengthsrË  Úbatch_numberss    `   rp   r„  z*BedrockGuardrail._bin_pack_bedrock_content%  s    ø€ ñ@ Ü˜'“NÐ$Ð$äÑuÐmtÔuÓuˆð	+œE¤#¤s (™Oð 	+´Sð 	+¼UÄ3ÌÀ8¹_õ 	+ñ  n´e¼JÀwÐPVÐ`fÔ<gÓ6hÐijÐikÐ6lÔmˆÜñ 
ä#¤C¨°wÓ$?ÑEYÔZô
ó 
ð 	
ro   c                 ó°  ‡— t        | «      dkD  r4t        dt        | «      dz  «      }t        | d| «      t        | |d «      fS | d   j                  d«      xs
 t	        «       }|j                  d«      xs d}t        |«      dk  ryt
        j                  |«      }|j                  d«      Šdt        d	t        fˆfd
„} ||d| «      f |||d «      ffS )aw  Bisect `content` into two roughly-equal, non-empty halves.

        When `content` already holds more than one item, it is split by list
        length. When it holds exactly one item, that item's own text is split
        instead (a list of length 1 has no items left to bisect, but one very
        long message is still a single content item) -- at the whitespace
        character nearest the midpoint rather than a raw character index, so
        the cut never lands inside a word/token. This is a plain, lossless
        cut with no overlap: concatenating the two fragments in order always
        reproduces the original text exactly, so merging back at
        ``_merge_logical_unit_outputs`` needs no reconciliation step.

        Known, accepted limitation: whitespace splitting only guards against
        *accidentally* severing a single token (one denied word, one PII
        pattern) across the cut. It does not, and cannot without an overlap
        window, stop a *multi-word* denied phrase deliberately positioned to
        straddle the boundary -- each fragment can scan clean on its own and
        still reassemble into the flagged phrase. AWS's own guidance on this
        API acknowledges the same gap for input chunking ("a critical piece of
        text could span two (or more) chunks if not carefully divided") with
        no documented resolution, and overlap-and-reconcile was evaluated and
        rejected for this PR: AWS's masking output has no documented
        length-preservation guarantee, so reconciling an overlap region against
        masked text is not sound in general. Out of scope for this PR.

        Returns None when there is nothing left to split -- a single item
        whose text is too short to halve into two non-empty pieces -- so the
        caller can give up and propagate the original too-large error instead
        of recursing forever.
        rù   r�  Nr   rf   rç   rê   Úpiecer…   c                 óR   •— ‰rt        | ‰¬«      nt        | ¬«      }t        |¬«      S )N)rf   rê   rÊ   )r7   r0   )rÜ  rÐ   rê   s     €rp   Úfragmentz9BedrockGuardrail._split_bedrock_content.<locals>.fragmentƒ  s+   ø€ áISÔ"¨¸*ÕEÔYkÐqvÔYwð ô &¨5Ô1Ð1ro   )	r×   Úmaxr|   r¢   r7   r�   Ú_nearest_whitespace_split_indexrl   r0   )rI   Úmidpointrë   rf   Úsplit_atrÞ  rê   s         @rp   r…  z'BedrockGuardrail._split_bedrock_contentV  så   ø€ ôD ˆw‹<˜!ÒÜ! !¤S¨£\°QÑ%6Ó7ˆHÜ˜  (Ð+Ó,¬e°G¸H¸IÐ4FÓ.GÐGÐGà% a™jŸn™n¨VÓ4ÒLÔ8JÓ8LˆØ"×&Ñ& vÓ.Ò4°"ˆÜˆt‹9�qŠ=ØÜ*×JÑJÈ4ÓPˆØ(×,Ñ,¨\Ó:ˆ
ð	2œCð 	2Ô$6õ 	2ñ ˜˜i˜x˜Ó)Ð+©h°t¸H¸I°Ó.GÐ-IÐIÐIro   rf   c                 ó   ‡ ‡— t        ‰ «      dz  Št        d„ t        j                  ‰ d‰«      D «       d¬«      }t        j	                  ‰ ‰«      }t        d„ ||r|j                  «       ndfD «       ˆfd„¬«      }t        ˆ fd	„|D «       ‰«      S )
a,  Return the index nearest `text`'s midpoint that falls on a whitespace
        boundary, so splitting `text[:i]` / `text[i:]` there never severs a word.

        Any Unicode whitespace counts, not just an ASCII space. Matching only `" "`
        would leave the boundary unguarded for exactly the payloads that get large
        enough to need splitting: JSON lines, source code, logs and transcripts are
        newline or tab delimited, so a deny-listed word sitting at the midpoint of
        one would be cut in half, scan clean on both fragments, and reassemble
        intact.

        The returned index always leaves both sides non-empty, which is what makes
        the caller's recursion terminate. A boundary that would put the split at 0
        or at ``len(text)`` is discarded: it would hand back a fragment identical to
        the text just rejected as too large, AWS would reject that again, and each
        retry would re-split it into the same unchanged fragment until the stack ran
        out. The dangerous shape is a text whose only space at or after the midpoint
        is its final character.

        Falls back to the raw midpoint when no usable whitespace boundary exists, either
        because `text` has none at all (a single giant token) or because the only
        candidates were degenerate. That is still a correct, lossless split, just no
        longer guaranteed word-safe for those cases. `text` must be at least two
        characters, which `_split_bedrock_content` guarantees, so the midpoint itself
        is never degenerate.
        r�  c              3   ó<   K  — | ]  }|j                  «       –— Œ y ­wr²   )Úend)r  Úfounds     rp   r  zCBedrockGuardrail._nearest_whitespace_split_index.<locals>.<genexpr>§  s   è ø€ Òf¨U˜UŸY™YŸ[Ñfùs   ‚r   N)Údefaultc              3   ó&   K  — | ]	  }|€Œ|–— Œ y ­wr²   rn   )r  Úsplits     rp   r  zCBedrockGuardrail._nearest_whitespace_split_index.<locals>.<genexpr>ª  s   è ø€ Òj�uÐX]ÑXiŒUÑjùs   ‚Šc                 ó    •— t        | ‰z
  «      S r²   )Úabs)ré  rá  s    €rp   r×  zBBedrockGuardrail._nearest_whitespace_split_index.<locals>.<lambda>«  s   ø€ œc %¨(Ñ"2Ó3€ ro   rØ  c              3   óR   •K  — | ]  }d |cxk  rt        ‰«      k  sŒn n|–— Œ  y­w©r   N)r×   )r  ré  rf   s     €rp   r  zCBedrockGuardrail._nearest_whitespace_split_index.<locals>.<genexpr>­  s!   øè ø€ ÒL˜u°a¸%Ô6KÄ#ÀdÃ)Ö6K”UÑLùs   ƒ'�
')r×   rß  rQ   ÚfinditerÚsearchr½   rå  Únext)rf   ÚbeforeÚafter_matchÚ
candidatesrá  s   `   @rp   rà  z0BedrockGuardrail._nearest_whitespace_split_index‹  s„   ù€ ô6 ˜d›) q™.ˆÜÑfÔ6I×6RÑ6RÐSWÐYZÐ\dÓ6eÔfÐptÔuˆÜ0×7Ñ7¸¸hÓGˆÜ"Ùj ¹k¨¯©Ô):ÈtÐ TÔjÛ3ô
ˆ
ô ÓL¨
ÔLÈhÓWÐWro   c                 óv   ‡— t        | t        «      sy| j                  «       Št        ˆfd„t        D «       «      S )aa  True if `detail` is an AWS error message for input exceeding the
        per-request text-unit quota.

        Matched on the message rather than the status code on purpose: AWS is not
        consistent about which error it raises for this. Observed against a live
        guardrail with an active content-filter policy, an oversized request comes
        back as a *ThrottlingException* (429) reading ``Input text size (3273 text
        units) exceeds the maximum allowed (1000 text units) for the content filter
        policy (Classic tier)``, while the documented failure mode is a
        ValidationException (400). Keying off the message covers both.

        A guardrail *block* is also raised as an HTTPException with status 400,
        but its ``detail`` is always a dict (built by
        ``_get_http_exception_for_blocked_guardrail``); a non-200 API error's
        ``detail`` is always the plain string returned by
        ``_parse_bedrock_guardrail_error_response``. Checking ``isinstance(detail,
        str)`` is therefore sufficient to never mistake a real block for a
        too-large error.
        Fc              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­wr²   rn   )r  Ú	substringÚlowereds     €rp   r  z=BedrockGuardrail._is_input_too_large_error.<locals>.<genexpr>Ç  s   øè ø€ Ò]¨I�9 Ô'Ñ]ùs   ƒ)r‡   rl   ÚlowerÚanyrL   )rh  r÷  s    @rp   rƒ  z*BedrockGuardrail._is_input_too_large_error¯  s/   ø€ ô* ˜&¤#Ô&ØØŸ™›ˆÜÓ]Ô9\Ô]Ó]Ð]ro   Úchunk_resultsc                 ó   — t         j                  | «      }t        d„ |D «       «      }|D ���cg c]  \  }}|D ]  }|‘Œ Œ }}}}t        d„ |D «       «      }t        d„ | D «       «      }d|v rdn|r|d   nd}	| D �
�cg c](  }
|
j                  j                  d«      xs g D ]  }|‘Œ Œ* }}
}t        d„ | D «       «      }t        t        | D �
��ci c]'  }
|
j                  j                  «       D ]  \  }}||“Œ
 Œ) c}}}
«      }|	�|	|d	<   |r|r
||d
<   ||d<   |r||d<   |rt         j                  | «      |d<   |S c c}}}w c c}}
w c c}}}
w )a	  Merge the per-chunk ApplyGuardrail responses of a chunked request into
        one, so a caller cannot tell whether chunking happened.

        Only ever called with responses that all passed (a block raises
        immediately from ``_apply_guardrail_content_with_chunking`` and is never
        added to this list). ``action`` is only set on the merged response when
        at least one chunk's raw response included it, and left absent otherwise
        -- mirroring a real single-call response and matching what
        ``_build_tracing_detail`` treats as "Bedrock didn't report an action".

        Fields this merge has no opinion on (``actionReason``, ``guardrailCoverage``,
        ``blockedResponse``, anything AWS adds later) are carried over from the chunk
        responses rather than dropped, so the response and the logged telemetry keep
        the shape a single unchunked call returned. The merged keys below win.

        Per AWS's documented ApplyGuardrail contract, a single call's ``outputs``
        is positionally parallel to the ``content`` items *of that call*: an
        entry per item when anything in the call was masked, or an empty list
        when nothing in the whole call was masked. Downstream masking
        (``_apply_masking_to_messages``) walks the merged ``outputs`` by a single
        running index across the *original, unchunked* message list, so a later
        chunk's masked text must land at the same global position it would have
        if chunking had never happened. Naively concatenating each chunk's
        ``outputs`` breaks that whenever a chunk had nothing masked (its empty
        list would otherwise silently swallow its items' slots, shifting every
        later chunk's masked text left onto the wrong message). So every
        item -- masked or not -- always contributes exactly one entry here,
        falling back to that item's own original (unmasked) text when its
        chunk returned no output for it; a wholly-untouched result is then
        collapsed back to an empty ``outputs`` list to match a real single-call
        no-op response. A chunk that returns a nonzero output count not equal
        to its item count is passed through as-is instead of guessed at, since
        AWS's docs don't cover partial masking within one multi-item call.
        c              3   óF   K  — | ]  }t         j                  |«      –— Œ y ­wr²   )r�   Ú_merge_logical_unit_outputs)r  Úunits     rp   r  zFBedrockGuardrail._merge_bedrock_guardrail_responses.<locals>.<genexpr>ð  s   è ø€ Ò'uÐ_cÔ(8×(TÑ(TÐUY×(ZÑ'uùrÔ  c              3   ó&   K  — | ]	  \  }}|–— Œ y ­wr²   rn   )r  rS  Úmaskeds      rp   r  zFBedrockGuardrail._merge_bedrock_guardrail_responses.<locals>.<genexpr>ô  s   è ø€ ÒI©9¨1¨f¤ÑIùrÍ  c              3   ó¤   K  — | ]H  }t        |j                  j                  d «      t        «      r|j                  j                  d «      –— ŒJ y­w)ÚactionN)r‡   rz   r¢   rl   ©r  Úchunk_results     rp   r  zFBedrockGuardrail._merge_bedrock_guardrail_responses.<locals>.<genexpr>ö  sD   è ø€ ò 
àÜ˜,×/Ñ/×3Ñ3°HÓ=¼sÔCð ×!Ñ!×%Ñ% h×/ñ
ùs   ‚AAÚGUARDRAIL_INTERVENEDrú   Nr‹   c              3   óR   K  — | ]  }|j                   j                  d «      –— Œ! y­w©rž  N©rz   r¢   r  s     rp   r  zFBedrockGuardrail._merge_bedrock_guardrail_responses.<locals>.<genexpr>  s!   è ø€ Ò'mÈ|¨×(=Ñ(=×(AÑ(AÀ'×(JÑ'mùs   ‚%'r  ÚoutputsÚoutputrž  )
r�   Ú_group_fragment_unitsr|   rù  rz   r¢   r   r4   r¾   Ú_sum_bedrock_guardrail_usage)rú  Úlogical_unitsÚper_unit_outputsr	  rS  r
  Úmerged_outputsÚ
any_maskedÚactionsÚmerged_actionr  Ú
assessmentÚmerged_assessmentsÚany_usage_reportedrÁ   rÂ   Úmergeds                    rp   rr  z3BedrockGuardrail._merge_bedrock_guardrail_responsesÉ  s¶  € ôL  0×EÑEÀmÓTˆÜ"'Ñ'uÐgtÔ'uÓ"uÐà%5÷!
ð !
Ù!�w ÀGò!
Ø:@ŠFð!
Øð!
ˆò !
ô  ÑIÐ8HÔIÓIˆ
äñ 
à -ô
ó 
ˆð '=ÀÑ&GÑ"Ñ]dÈgÐVXÊkÐjnð 	ð
 !.÷%
àØ+×4Ñ4×8Ñ8¸ÓGÒMÈ2ò%
ð ò ð%
Øð%
Ðñ %
ô
 %(Ñ'mÐ_lÔ'mÓ$mÐä26Ü$à/<÷ð Ø+È|×OdÑOd×OjÑOjÓOlòÙAKÀÀe��U‘
ðØôó3
ˆð Ð$Ø,ˆF�8ÑÙ™jØ .ˆF�9ÑØ-ˆF�8ÑÙØ$6ˆF�=Ñ!ÙÜ.×KÑKÈMÓZˆF�7‰OØˆùôG!
ùó%
ùôs   ®D<Á=-EÃ,E	c                 óL   — t         j                  t        d„ | D «       «      «      S )a-  Sum each chunk's ``usage`` counters field-by-field into one totals dict.

        Keys are taken from the responses rather than from a fixed list, so a counter
        this code does not know about (AWS has added several) is still summed and
        reported instead of being silently dropped to zero.c              3   óZ   K  — | ]#  }|j                   j                  d «      xs i –— Œ% y­wr  r  r  s     rp   r  z@BedrockGuardrail._sum_bedrock_guardrail_usage.<locals>.<genexpr>   s1   è ø€ ò à ð ×%Ñ%×)Ñ)¨'Ó2Ò8°bÓ8ñùs   ‚)+)r�   r±  r|   )rú  s    rp   r  z-BedrockGuardrail._sum_bedrock_guardrail_usage  s,   € ô  ×3Ñ3Üñ à$1ôó ó
ð 	
ro   Úusagesc                 ó¦   ‡— t        t        t        j                  d„ | D «       «      D �‡ci c]  Š‰t	        ˆfd„| D «       «      “Œ c}«      S c c}w )Nc              3   ó.   K  — | ]  }|D ]  }|–— Œ Œ y ­wr²   rn   ©r  rž  rÁ   s      rp   r  z7BedrockGuardrail._sum_usage_counters.<locals>.<genexpr>,  s   è ø€ Ò(R°ÈEÒ(RÀS¬Ð(R¨Ñ(Rùr~  c              3   óH   •K  — | ]  }|j                  ‰«      xs d –— Œ y­wrí  rÄ  r  s     €rp   r  z7BedrockGuardrail._sum_usage_counters.<locals>.<genexpr>+  s!   øè ø€ ÒA°˜Ÿ™ 3›Ò,¨1Ó,ÑAùs   ƒ")r   r5   rˆ   Úfromkeysr  )r  rÁ   s    `rp   r±  z$BedrockGuardrail._sum_usage_counters&  sO   ø€ äÜ!ô  Ÿ=™=Ñ(R¸&Ô(RÓR÷àð ”SÓA¸&ÔAÓAÑAòó
ð 	
ùòs   «A
c                 ó&  ‡ — dt         t        t        f   dt        dt         t        t        f   fd„}t        d„ t	        t        t        ‰ |d¬«      «      dd	 «      D «       «      }t        ˆ fd
„t        ||dd	 t        ‰ «      fz   «      D «       «      S )a  Group consecutive text-fragment chunk results back into the one content
        item each group came from, leaving every ordinary chunk result as a unit of
        one.

        The group size is read off the results themselves rather than assumed,
        because a single content item can be bisected repeatedly: two levels of
        splitting yield four fragments for one item, not two. Assuming a fixed pair
        here would emit two outputs for one message and shift every later message's
        masked text onto the wrong message.rÇ  r}  r…   c                 óZ   — | \  }}|dk(  rt        d|j                  «      dz
  dfS |dz
  dfS )Nr   rù   TF)rß  r{   )rÇ  r}  Ú	remainingrS  s       rp   Úadvancez7BedrockGuardrail._group_fragment_units.<locals>.advance>  s>   € Ø"‰LˆI�qØ˜AŠ~Ü˜1˜f×8Ñ8Ó9¸AÑ=¸tÐCÐCØ˜q‘= %Ð'Ð'ro   c              3   ó0   K  — | ]  \  }\  }}|r|–— Œ y ­wr²   rn   )r  rü   rS  Ústarts_units       rp   r  z9BedrockGuardrail._group_fragment_units.<locals>.<genexpr>D  s$   è ø€ ò 
á'�Ñ'˜˜;Ùô ñ
ùs   ‚)r   FrÎ  rù   Nc              3   ó@   •K  — | ]  \  }}t        ‰|| «      –— Œ y ­wr²   rÒ  )r  Ústartrå  rú  s      €rp   r  z9BedrockGuardrail._group_fragment_units.<locals>.<genexpr>I  s!   øè ø€ Òw¹¸À”U˜=¨¨sÐ3×4Ñwùs   ƒ)r|   rw   rƒ   ry   r	  r   r#  r×   )rú  r"  Ústartss   `  rp   r  z&BedrockGuardrail._group_fragment_units0  sž   ø€ ð	(œU¤3¬ 9Ñ-ð 	(Ô7Pð 	(ÔUZÔ[^Ô`dÐ[dÑUeó 	(ô ñ 
ä+4´U¼:ÀmÐU\ÐfpÔ;qÓ5rÐstÐsuÐ5vÓ+wô
ó 
ˆô
 ÓwÄsÈ6ÐSYÐZ[ÐZ\ÐS]ÔadÐerÓasÐ`uÑSuÓGvÔwÓwÐwro   rþ  c                 ó:  ‡‡— t        | «      dkD  rhdt        dt        t        df   fd„Šdt        dt        fˆfd„Šdj                  ˆfd„| D «       «      }t        ˆfd	„| D «       «      }t        |¬
«      f|fS | \  }|j                  j                  d«      xs |j                  j                  d«      xs d}t        |«      t        |j                  «      k(  rt        |«      t        |«      fS |st        d„ |j                  D «       «      dfS t        |«      dfS )aS  Reduce one logical unit (a fragment group of any size, or a single chunk
        result) to the ``BedrockGuardrailOutput`` entries it contributes to the
        merged response, plus whether any masking actually happened in it.

        Per AWS's documented ApplyGuardrail contract, a single call's
        ``outputs`` is positionally parallel to the ``content`` items *of that
        call*: an entry per item when anything in the call was masked, or an
        empty list when nothing in the whole call was masked. Downstream
        masking (``_apply_masking_to_messages``) walks the merged ``outputs``
        by a single running index across the *original, unchunked* message
        list, so a later chunk's masked text must land at the same global
        position it would have if chunking had never happened. So every item
        -- masked or not -- always contributes exactly one entry here, falling
        back to that item's own original (unmasked) text when its chunk
        returned no output for it. A chunk that returns a nonzero output count
        not equal to its item count is passed through as-is instead of guessed
        at, since AWS's docs don't cover partial masking within one multi-item
        call.

        A unit holding more than one result is a fragment group: every result in it
        is one fragment of a single content item's text, so the group collapses to
        one entry built from each fragment's masked text (or that fragment's own
        original text where it came back unmasked), concatenated in order. This
        holds for any group size, not only two.
        rù   r}  r…   .c                 óŒ   — t        | j                  j                  d«      xs | j                  j                  d«      xs d«      S )Nr	  r
  rn   )r|   rz   r¢   )r}  s    rp   Úfragment_outputszFBedrockGuardrail._merge_logical_unit_outputs.<locals>.fragment_outputsj  s7   € Ü˜VŸ_™_×0Ñ0°Ó;Òb¸v¿¹×?RÑ?RÐS[Ó?\ÒbÐ`bÓcÐcro   c                 óº   •— | j                   d   j                  d«      xs i j                  d«      xs d} ‰| «      }|r|d   j                  d«      nd }|�|S |S )Nr   rf   rç   )rI   r¢   )r}  rJ   r	  r   r*  s       €rp   Úfragment_textzCBedrockGuardrail._merge_logical_unit_outputs.<locals>.fragment_textm  sl   ø€ Ø!'§¡°Ñ!2×!6Ñ!6°vÓ!>Ò!DÀ"× IÑ IØó!ò !àð ñ "2°&Ó!9�Ù:A ¨¡
§¡¨vÔ 6Àt�Ø!'Ð!3�vÐ?¸Ð?ro   rç   c              3   ó.   •K  — | ]  } ‰|«      –— Œ y ­wr²   rn   )r  r}  r,  s     €rp   r  z?BedrockGuardrail._merge_logical_unit_outputs.<locals>.<genexpr>u  s   øè ø€ Ò(RÀ6©°v×)>Ñ(Rùó   ƒc              3   ó.   •K  — | ]  } ‰|«      –— Œ y ­wr²   rn   )r  r}  r*  s     €rp   r  z?BedrockGuardrail._merge_logical_unit_outputs.<locals>.<genexpr>v  s   øè ø€ Ò#PÀÑ$4°V×$<Ñ#Pùr.  rÊ   r	  r
  rn   c              3   ó€   K  — | ]6  }t        |j                  d «      xs i j                  d «      xs d¬«      –— Œ8 y­w)rf   rç   rÊ   N)r2   r¢   r   s     rp   r  z?BedrockGuardrail._merge_logical_unit_outputs.<locals>.<genexpr>~  sE   è ø€ ò ð ô 'ØŸ(™( 6Ó*Ò0¨b×5Ñ5°fÓ=ÒCÀ÷ð ñùs   ‚<>FT)r×   ry   r|   r2   rl   Újoinrù  rz   r¢   rI   rƒ   )rþ  Úmerged_textr  r  Úchunk_outputsr*  r,  s        @@rp   rý  z,BedrockGuardrail._merge_logical_unit_outputsK  s+  ù€ ô: ˆt‹9�qŠ=ðdÔ)Bð dÄuÔMcÐehÐMhÑGió dð@Ô&?ð @ÄCõ @ð "$§¡Ó(RÈTÔ(RÓ!RˆKÜ #Ó#PÈ4Ô#PÓ PˆJÜ*°Ô<Ð>À
ÐJÐJà‰ˆØ+×4Ñ4×8Ñ8¸ÓCÒpÀ|×G\ÑG\×G`ÑG`ÐaiÓGjÒpÐnpˆÜˆ}Ó¤ \×%9Ñ%9Ó!:Ò:Ü˜Ó'¬¨mÓ)<Ð<Ð<ÙÜñ ð )×0Ñ0ô	ó ð
 ðð ô �]Ó# TÐ)Ð)ro   r™  r9   rš  c              ƒ   ó4  K  — 	 | j                   j                  |j                  |j                  |j                  ¬«      ƒ d{  –—† S 7 Œ# t
        $ r ‚ t        $ �r¸}t        |dd«      }t        |t        j                  «      rË	 | j                  |«      \  }}	|r˜| j                  | j                  d|	i|xs i d|j                  «       t        j                   t"        j$                  «      j                  «       t        j                   t"        j$                  «      |z
  j'                  «       |¬«       t        ||	¬«      |‚# t
        $ r ‚ w xY wt)        j*                  dt-        |«      «       | j                  | j                  dt-        |«      i|xs i d|j                  «       t        j                   t"        j$                  «      j                  «       t        j                   t"        j$                  «      |z
  j'                  «       |¬«       ‚ d}~ww xY w­w)	aH  POST a signed Bedrock request, logging+raising on network/HTTP errors.

        Shared by both the ApplyGuardrail and InvokeGuardrailChecks paths so their
        transport-error handling cannot drift. Returns the raw ``httpx.Response`` on
        success (including non-2xx that httpx did not raise on); the 200-path logging,
        status and tracing stay with each caller because the two APIs report differently.

        ``log_transport_failure=False`` suppresses the ``guardrail_failed_to_respond``
        entry for a non-200 that is re-raised as an ``HTTPException``, for callers that
        own consolidated per-request logging. The ApplyGuardrail path needs this:
        ``AsyncHTTPHandler.post`` calls ``raise_for_status()``, so every non-200 lands
        in this handler, and one logical request can legitimately produce several of
        them (a too-large probe, then each rejected bisection level) while still
        succeeding overall. Logging per attempt would report a recovered request as
        several failures plus a success.

        The connection-level branch below (timeout, endpoint down) still logs
        unconditionally: it re-raises the original exception rather than an
        ``HTTPException``, so no consolidating caller catches it, and suppressing it
        would drop the only record of the failure.
        )rH  r;  rI  Nrz   r¤  r¾  ©r¡   r¬  r  r­  re  r®  r¯  rd  r’  z0Bedrock AI: failed to make guardrail request: %s)r    ÚpostrH  ÚbodyrI  r   r»  rª   r‡   ÚhttpxÚResponser£  r³  r¡   rµ  r   rj  r   rk  r¶  r   r¤  rl   )
r®   r™  r  rd  re  rš  ÚeÚerr_responser“  r¨  s
             rp   rŸ  zBedrockGuardrail._sign_and_post†  sã  è ø€ ð:/	Ø×+Ñ+×0Ñ0Ø$×(Ñ(Ø%×*Ñ*Ø(×0Ñ0ð 1ó ÷ ð ð ùô
 ò 	àÜó &	ô #*¨!¨Z¸Ó">ˆLÜ˜,¬¯©Ô7ðð ×DÑDÀ\ÓRñØ#Ø&á,Ø×WÑWØ/3×/FÑ/Fà '¨ð5ð *6Ò);¸Ø-JØ'1×';Ñ';Ó'=Ü%-§\¡\´(·,±,Ó%?×%IÑ%IÓ%KÜ&.§l¡l´8·<±<Ó&@À:Ñ&M×%\Ñ%\Ó%^Ø'1ð Xô ô (°KÈÔWÐ]^Ð^øÜ$ò Øðúô !×&Ñ&Ð'YÔ[^Ð_`Ó[aÔbØ×KÑKØ#'×#:Ñ#:Ø)0´#°a³&Ð(9Ø)Ò/¨RØ!>Ø%×/Ñ/Ó1Ü!Ÿ™¤h§l¡lÓ3×=Ñ=Ó?Ü"Ÿ,™,¤x§|¡|Ó4°zÑA×PÑPÓRØ%ð Lô 	ð ûðM&	üsN   ‚H„?A
 ÁAÁA
 ÁHÁA
 Á
HÁ'HÂB<EÅEÅCHÈHÈHrí   )rò   Ú	assistantra   c                 ó²   — t         }t        dt        |«      |«      D ��cg c]%  }t        | ||||z    D �cg c]  }d|i‘Œ c}¬«      ‘Œ' c}}S c c}w c c}}w )aJ  Group ``texts`` into role-tagged messages of <= the API content-block cap.

        A source message with more text blocks than the per-message limit is split
        across multiple messages so EVERY block is scanned. Truncating instead would
        let a user hide prohibited content past the limit (guardrail bypass).
        r   rf   r  )rT   rû   r×   r.   )rí   r  Úcapr&  rf   s        rp   Ú!_chunk_texts_into_checks_messagesz2BedrockGuardrail._chunk_texts_into_checks_messagesÖ  se   € ô 8ˆô ˜q¤# e£*¨cÓ2÷
ð
 ô	 !ØØ49¸%À%È#Á+Ð4NÖO¨D˜& $šÒOöó
ð 	
ùò Pùó
s    AµAÁ 
AÁAc                 óÖ  — |dk(  rm| j                  |¬«      }|j                  d«      xs g D �cg c]+  }|j                  d«      xs i j                  d«      x}sŒ*|‘Œ- }}| j                  d|«      S |xs g D ��	�
cg c]S  }| j                  d| j                  |«      xs g D �
cg c]  }
|
j                  sŒ|
j                  ‘Œ c}
«      D ]  }	|	‘Œ ŒU c}
}	}S c c}w c c}
w c c}
}	}w )a:  Build the role-tagged `messages` array for InvokeGuardrailChecks.

        INPUT scans the request messages, OUTPUT scans the model response as an
        ``assistant`` turn. Every non-empty text block of every message is scanned;
        messages exceeding the per-message content-block cap are split into multiple
        messages rather than truncated.

        INPUT content is tagged ``user`` regardless of the caller-supplied role.
        Bedrock excludes ``system`` content from prompt-attack evaluation, so
        trusting a caller's ``system``/``developer`` label would let an injection
        avoid the promptAttack check. At the proxy every INPUT message is
        caller-controlled, so all of it is treated as untrusted user input, matching
        AWS guidance to tag untrusted content as user input.
        rÓ   rª  rI   rf   r<  rò   )rÛ   r¢   r?  rË   rf   )r®   rJ   rÄ   rz   Úoutput_requestrè   rf   Úoutput_textsrÉ   Úchecks_messagerÐ   s              rp   Ú'_build_invoke_guardrail_checks_messagesz8BedrockGuardrail._build_invoke_guardrail_checks_messagesé  s  € ð( �XÒð %)×$OÑ$OÐYaÐ$OÓ$bˆNà!/×!3Ñ!3°IÓ!>Ò!DÀ"ö#ØÐRV×RZÑRZÐ[aÓRbÒRhÐfh×QmÑQmÐntÓQuÐIuÈÑIu’ð#ˆLð #ð ×9Ñ9¸+À|ÓTÐTð $š> r÷
ð 
àØ"&×"HÑ"HØØ)-×)KÑ)KÈGÓ)TÒ)ZÐXZÖi Ð^c×^hÓ^h�—“Òió#ò
ð ò ð
Øô
ð 	
ùò#ùò jùô
s)   ¯+CÁCÁ=(C$Â%CÂ7CÃC$ÃC$c              ƒ   ó  K  — t        j                  t        j                  «      }| j	                  |||¬«      }|s
t        «       S | j                  «       \  }}	|| j                  dœ}
|r|j                  d«      nd}| j                  ||
| j                  |	|t        ¬«      }t        j                  d|j                  «       |xs% |dk(  rt        j                   nt        j"                  }| j%                  ||||¬«      ƒ d{  –—† }|j&                  d	k7  rÚ| j)                  |«      \  }}t        j*                  d
|j&                  |«       | j-                  | j.                  d|i|xs i d|j1                  «       t        j                  t        j                  «      j1                  «       t        j                  t        j                  «      |z
  j3                  «       |¬«       t5        ||¬«      ‚	 t7        t8        «      j;                  |j=                  «       «      }| jE                  |«      }| j-                  | j.                  | jG                  |«      |xs i | jI                  tK        |«      «      |j1                  «       t        j                  t        j                  «      j1                  «       t        j                  t        j                  «      |z
  j3                  «       ||r| jM                  |«      nd¬«	       |r| jO                  ||¬«      ‚t        «       S 7 �Œ# t>        t@        f$ rÕ}t        j*                  dtC        |«      «       | j-                  | j.                  dtC        |«      i|xs i d|j1                  «       t        j                  t        j                  «      j1                  «       t        j                  t        j                  «      |z
  j3                  «       |¬«       t5        dddi¬«      |‚d}~ww xY w­w)aM  Run the resource-less InvokeGuardrailChecks API and enforce thresholds.

        Detect-only: the API returns scores, never rewritten content. We map scores
        to a block decision via the configured thresholds. On a pass we return an
        empty ``BedrockGuardrailResponse`` (downstream masking treats it as a no-op).
        r`  )rÄ   r”   r<  N)r9  r;  r¤   r-  r<  r>  z-Bedrock InvokeGuardrailChecks request url: %srÆ   )r™  r  rd  re  r›  z<Bedrock InvokeGuardrailChecks: error response. Status %s: %sr¤  r¾  r5  r’  z;Bedrock InvokeGuardrailChecks: unparseable 200 response: %sr‘  zCBedrock InvokeGuardrailChecks returned an unexpected response shaper«  ra  )(r   rj  r   rk  rD  r4   r:  r”   r¢   rY  r¤   rR   r   r¬   rH  r+   r³   r´   rŸ  r“  r£  r¤  r³  r¡   rµ  r¶  r   r   r1   Úvalidate_pythonrL  r   r¥   rl   Ú!_collect_invoke_checks_violationsÚ,_sanitize_invoke_checks_response_for_loggingÚ_get_invoke_checks_statusrƒ   Ú#_build_invoke_checks_tracing_detailÚ_get_block_exception_for_checks)r®   rJ   rÄ   rz   r  rZ  re  Úchecks_messagesr9  r-  r7  r<  r™  rd  rœ  r“  r¨  r�  r:  Ú
violationss                       rp   r\  z6BedrockGuardrail._make_invoke_guardrail_checks_request  s¨  è ø€ ô %ŸL™L¬¯©Ó6ˆ
à!%×!MÑ!MØ H°xð "Nó "
ˆñ ä+Ó-Ð-à'+×'=Ñ'=Ó'?Ñ$ˆ�_Ø3BÈdÏkÉkÑ&ZˆÙDP \×%5Ñ%5°iÔ%@ÐVZˆà"&×"7Ñ"7Ø#ØØ ×0Ñ0Ø+ØÜ>ð #8ó #
Ðô 	×"Ñ"Ð#RÐTd×ThÑThÔià.ò 
Ø,2°gÒ,=Ô×(Ò(ÔCV×C`ÑC`ð 	ð '+×&9Ñ&9Ø-Ø%Ø!Ø!ð	 ':ó '
÷ !
ˆð ×%Ñ%¨Ò,Ø*.×*VÑ*VÐWeÓ*fÑ'ˆK˜Ü ×&Ñ&ØNØ×*Ñ*Øôð
 ×KÑKØ#'×#:Ñ#:Ø)0°.Ð(AØ)Ò/¨RØ!>Ø%×/Ñ/Ó1Ü!Ÿ™¤h§l¡lÓ3×=Ñ=Ó?Ü"Ÿ,™,¤x§|¡|Ó4°zÑA×PÑPÓRØ%ð Lô 	ô  ¨KÀÔOÐOð	Ü#.Ô/MÓ#N×#^Ñ#^Ð_m×_rÑ_rÓ_tÓ#uˆMð" !×BÑBÀ=ÓQˆ
ð 	×GÑGØ#×6Ñ6Ø$(×$UÑ$UÐVcÓ$dØ%Ò+¨Ø!×;Ñ;¼DÀÓ<LÓMØ!×+Ñ+Ó-Ü—\‘\¤(§,¡,Ó/×9Ñ9Ó;Ü—l‘l¤8§<¡<Ó0°:Ñ=×LÑLÓNØ!ÙS]˜4×CÑCÀJÔOÐcgð 	Hô 
	
ñ Ø×6Ñ6°zÐP\Ð6Ó]Ð]ä'Ó)Ð)ð!
úô8  ¤Ð,ò 	Ü ×&Ñ&Ð'dÔfiÐjkÓflÔmØ×KÑKØ#'×#:Ñ#:Ø)0´#°a³&Ð(9Ø)Ò/¨RØ!>Ø%×/Ñ/Ó1Ü!Ÿ™¤h§l¡lÓ3×=Ñ=Ó?Ü"Ÿ,™,¤x§|¡|Ó4°zÑA×PÑPÓRØ%ð Lô 	ô  ØØÐ!fÐgôð ðûð	üs9   ‚DP	ÄLÄC-P	Ç2,L" ÈDP	Ì"PÌ1CPÐPÐP	c                 ó¶  — t        |xs i j                  d«      xs i «      }ddd| j                  fddd| j                  fddd| j                  fg}| j
                  xs i }g }|D ]ð  \  }}}}	|	�||vrŒ|j                  |«      xs i }
|dk(  r%|
j                  d	«      r|j                  |d
dœ«       |
j                  d«      xs g D ]‹  }|j                  |«      }t        |t        t        f«      sŒ+t        |«      |	k\  sŒ:|dk(  r||j                  d«      t        |«      dœn||j                  d«      t        |«      dœ}|j                  |«       Œ� Œò |S )a  Return the check results whose score meets/exceeds the configured threshold.

        Only checks present in the configured ``checks`` block are evaluated; a
        threshold of ``None`` makes that check detect-only (never contributes a
        violation). A truncated sensitiveInformation result counts as a violation
        (fail closed: omitted detections were never scored). Only the non-sensitive
        label (category/type) and the numeric score are kept -- never offsets or
        matched text.
        r|  rV   ÚseverityScoreÚcategoryrU   rW   ÚconfidenceScoreræ   Ú	truncatedT)ÚcheckrR  )rS  rP  rO  )rS  ræ   rQ  )
rˆ   r¢   r•   r–   r—   r”   rÌ   r‡   rw   Úfloat)r®   rz   r|  Úcheck_specsÚconfigured_checksrM  Ú	check_keyÚscore_fieldÚlabel_fieldÚ	thresholdÚcheck_resultÚentryÚscoreÚ	violations                 rp   rG  z2BedrockGuardrail._collect_invoke_checks_violationsz  sŒ  € ô *.¨xª~¸2×.BÑ.BÀ9Ó.MÒ.SÐQSÓ)Tˆð
  ØØØ×-Ñ-ð	ð ˜_¨j¸$×:VÑ:VÐWà&Ø!ØØ×-Ñ-ð	ð
ˆð  $(§;¡;Ò#4°"ÐØ:<ˆ
Ø>Iò 	1Ñ:ˆI�{ K°ØÐ  IÐ5FÑ$FØØ"Ÿ;™; yÓ1Ò7°RˆLØÐ2Ò2°|×7GÑ7GÈÔ7TØ×!Ñ!¨IÀDÑ"IÔJØ%×)Ñ)¨)Ó4Ò:¸ò 1�ØŸ	™	 +Ó.�Ü˜e¤c¬5 \Õ2´u¸U³|ÀyÓ7Pð '¨/Ò9ð #,¸¿¹À:Ó9NÔafÐglÓamÒnà'0¸%¿)¹)ÀFÓ:KÔ`eÐfkÓ`lÑmð ð
 ×%Ñ% iÕ0ñ1ð	1ð Ðro   c                 ó"  — t        j                  t        | «      «      }|j                  d«      xs i j                  d«      xs i }|j                  d«      xs g D ]0  }t	        |t        «      sŒt
        D ]  }|j                  |d«       Œ Œ2 |S )zFStrip PII location offsets from a checks response before it is logged.r|  rW   N)ÚcopyÚdeepcopyrˆ   r¢   r‡   r]   Úpop)rz   Ú	sanitizedÚ	sensitiver\  rÁ   s        rp   rH  z=BedrockGuardrail._sanitize_invoke_checks_response_for_logging¬  s‡   € ô
 ,0¯=©=¼¸h»Ó+Hˆ	Ø%ŸM™M¨)Ó4Ò:¸×?Ñ?Ð@VÓWÒ]Ð[]ˆ	Ø—]‘] 9Ó-Ò3°ò 	)ˆEÜ˜%¤Õ&Ü<ò )�CØ—I‘I˜c 4Õ(ñ)ð	)ð Ðro   Úover_thresholdc                 ó   — | rdS dS )NÚguardrail_intervenedr¿  rn   )re  s    rp   rI  z*BedrockGuardrail._get_invoke_checks_status¹  s   € á)7Ð%ÐF¸YÐFro   rM  c                 ó„   — i }d„ | D «       D �cg c]  }t        |t        «      r|r|‘Œ }}|r||d<   | rdnd|d<   |S c c}w )Nc              3   ód   K  — | ](  }|j                  d «      xs |j                  d«      –— Œ* y­w)rP  ræ   NrÄ  )r  Úvs     rp   r  zGBedrockGuardrail._build_invoke_checks_tracing_detail.<locals>.<genexpr>Ä  s)   è ø€ ÒQÀ˜!Ÿ%™% 
Ó+Ò<¨q¯u©u°V«}Ó<ÑQùs   ‚.0Úviolation_categoriesr  ÚNONEÚguardrail_action)r‡   rl   )rM  r°  ÚlabelÚ
categoriess       rp   rJ  z4BedrockGuardrail._build_invoke_checks_tracing_detail½  sf   € ð 9;ˆñ RÀjÔQö
àÜ˜%¤Ô%©%ò ð
ˆ
ð 
ñ
 Ø5?ˆNÐ1Ñ2ÙGQÑ-CÐW]ˆÐ)Ñ*ØÐùò
s   Ž=c                 óœ   — | j                   du r/|xs i }t        d|j                  dd«      || j                  ¬«      S t	        dd|dœ¬«      S )	a  Build the block exception for an over-threshold InvokeGuardrailChecks result.

        Mirrors ``_get_http_exception_for_blocked_guardrail``'s return-type branching.
        The detail carries only non-sensitive labels + scores (no offsets / raw input).
        TúViolated guardrail policyÚmodelúbedrock-guardrail©rÉ   rr  r  rn  é�  )r¤  Úbedrock_guardrail_checksr’  )r“   r   r¢   rn  r   )r®   rM  r  Ú_request_datas       rp   rK  z0BedrockGuardrail._get_block_exception_for_checksÌ  sf   € ð ×*Ñ*¨dÑ2Ø#/Ò#5°2ˆMÜ*Ø3Ø#×'Ñ'¨Ð1DÓEØ*Ø#×2Ñ2ô	ð ô Øà4Ø,6ñô
ð 	
ro   c                 óê  — d}	 t        |dd«      }t        |«      r |«       }|€{	 t        |dd«      }t        |t        t
        f«      r%t        j                  |j                  d«      «      }n2t        |dd«      }t        |t        «      rt        j                  |«      }t        |t        «      syd|j                  di «      j                  d	d
«      v S # t        $ r d}Y Œ¿w xY w# t        $ r Y yw xY w)z³
        Return True if the Bedrock ApplyGuardrail response indicates an exception.

        Works with real httpx.Response objects and MagicMock responses used in tests.
        NrL  rI   rB  rf   Fr»  r¼  r½  rç   )rª   Úcallabler»  r‡   ÚbytesÚ	bytearrayrL  ÚloadsÚdecoderl   rˆ   r¢   )r®   rz   ÚpayloadÚjson_methodr¿   rf   s         rp   Ú%_check_bedrock_response_for_exceptionz6BedrockGuardrail._check_bedrock_response_for_exceptionä  sì   € ð ˆð	Ü!(¨°6¸4Ó!@ˆKÜ˜Ô$Ù%›-�ð ˆ?ð
Ü$ X¨y¸$Ó?�Ü˜c¤E¬9Ð#5Ô6Ü"Ÿj™j¨¯©°GÓ)<Ó=‘Gä")¨(°F¸DÓ"A�DÜ! $¬Ô,Ü"&§*¡*¨TÓ"2˜ô
 ˜'¤4Ô(Øà˜gŸk™k¨(°BÓ7×;Ñ;¸HÀbÓIÐIÐIøô' ò 	ØŠGð	ûô ò áðús#   „C ¦A:C& ÃC#Ã"C#Ã&	C2Ã1C2c                 óÄ   — |j                   dk(  rB| j                  |«      ry	 |j                  «       }t        di |¤Ž}| j	                  |«      ry	 yy# t
        $ r Y yw xY w)a.  
        Get the status of the bedrock guardrail response.

        Returns:
            "success": Content allowed through with no violations
            "guardrail_intervened": Content blocked due to policy violations
            "guardrail_failed_to_respond": Technical error or API failure
        r›  r¾  rg  r¿  rn   )r“  r€  rL  r4   r   r»  )r®   rz   r¥  r¦  s       rp   r´  z7BedrockGuardrail._get_bedrock_guardrail_response_status  sx   € ð ×Ñ 3Ò&Ø×9Ñ9¸(ÔCØ4ðØ(0¯©«�Ü4LÑ4^È~Ñ4^Ð*Ø×AÑAÐB\Ô]Ø1ð ^ð
 Ø,øô	 ò Øàðús   £,A Á	AÁAc                 ó  — |j                   }d}	 |j                  «       }t	        |t        «      r�t	        |j                  d«      t
        «      r||d   fS |j                  d«      }t	        |t        «      r&t	        |j                  d«      t
        «      r||d   fS t	        |t
        «      r||fS ||fS # t        $ rL t        |dd«      xs d}t	        |t
        «      r$|j                  «       r||j                  «       fcY S ||fcY S w xY w)zÿ
        Parse AWS Bedrock guardrail error response body to extract status code and message.

        AWS may return shapes like {"message": "..."} or {"error": {"message": "..."}}.
        Returns (status_code, message) for use in HTTPException.
        z Bedrock guardrail request failedrf   Nrç   rÉ   r¤  )	r“  rL  r»  rª   r‡   rl   Ústriprˆ   r¢   )r®   rz   r“  rÉ   r7  rf   Úerrs          rp   r£  z8BedrockGuardrail._parse_bedrock_guardrail_error_response  sý   € ð &×1Ñ1ˆØ;ˆð	*Ø"Ÿ-™-›/ˆDô �dœDÔ!Ü˜$Ÿ(™( 9Ó-¬sÔ3Ø# T¨)¡_Ð5Ð5ØŸ™ 'Ó*ˆCÜ˜#œtÔ$¬°C·G±G¸IÓ4FÌÔ)LØ# S¨¡^Ð4Ð4Ü˜#œsÔ#Ø# SÐ)Ð)Ø˜WÐ%Ð%øô ò 	*Ü! (¨F°DÓ9Ò?¸RˆDÜ˜$¤Ô$¨¯©¬Ø# T§Z¡Z£\Ð2Ò2Ø Ð)Ò)ð		*ús   �B5 Â5AD
ÄD
Ä	D
c                 ój  — i }| j                  |«      }|r||d<   |j                  d«      }t        |t        «      r||d<   |j                  d«      }t        |t        «      rK|j                  «       D ��ci c]  \  }}t        |t        «      sŒ||“Œ }	}}|	r|	|d<   t        |	|¬«      |d<   |S c c}}w )aø  
        Build the tracing detail from the raw Bedrock response, before
        redaction, so downstream loggers (OTEL, Langfuse, ...) get the
        actual category names rather than the "[REDACTED]" sentinel that
        replaces customWords.match later. Bedrock's top-level ``action``
        field ("GUARDRAIL_INTERVENED" or "NONE") is also surfaced so the
        OTEL integration can expose it as a queryable span attribute
        without re-parsing the redacted guardrail_response blob.
        rk  r  rm  rž  Úguardrail_usage)Úusage_unitsr-  Úguardrail_cost)Ú!_extract_violation_category_namesr¢   r‡   rl   rˆ   r¾   rw   r   )
r®   rz   r-  r°  rk  Úbedrock_actionrž  rÁ   rÂ   r‡  s
             rp   r²  z&BedrockGuardrail._build_tracing_detail8  sÇ   € ð 9;ˆØ&*×&LÑ&LÈXÓ&VÐÙØ5IˆNÐ1Ñ2Ø (§¡¨XÓ 6ˆÜ�n¤cÔ*Ø1?ˆNÐ-Ñ.Ø—|‘| GÓ,ˆÜ�eœTÔ"à-2¯[©[«]÷"Ù)˜s E¼jÈÔPSÕ>T��U‘
ð"ˆKñ "ñ Ø4?�Ð0Ñ1Ü3IØ +¸_ô4�Ð/Ñ0ð Ðùó"s   Á5B/ÂB/c                 óþ   — g }| j                  |«      D ]f  }|j                  dg «      xs g D ]K  }|j                  d«      xs |j                  d«      }t        |t        «      sŒ8|sŒ;|j	                  |«       ŒM Œh |S )u`  
        Flatten the BLOCKED assessments into a list of human-readable category
        names suitable for queryable OTEL / standard-logging attributes.

        SECURITY: only emits the non-sensitive policy *label* (topic name,
        content-filter type, PII entity type, named-regex name). The raw
        ``match`` field is intentionally NOT used â€” it carries the user's
        original input that triggered the rule (e.g. a credit-card number
        that hit a regex, or the literal custom word). Surfacing it to
        telemetry would re-introduce the sensitive content the guardrail
        was supposed to keep out. Entries that only have a ``match`` (bare
        customWords, unnamed regexes) are therefore skipped â€” operators
        can still see the count in ``_extract_blocked_assessments`` which
        feeds the HTTP error detail.
        ÚmatchesÚnameræ   )Ú_extract_blocked_assessmentsr¢   r‡   rl   rÌ   )r®   rz   ÚnamesrÐ   Úmatchrn  s         rp   r‰  z2BedrockGuardrail._extract_violation_category_namesW  s   € ð  #%ˆØ×6Ñ6°xÓ@ò 	(ˆEØŸ™ 9¨bÓ1Ò7°Rò (�ð Ÿ	™	 &Ó)Ò>¨U¯Y©Y°vÓ->�Ü˜e¤SÕ)ªeØ—L‘L Õ'ñ(ð	(ð ˆro   c                 óR  — g }|j                  dg «      xs g }|D �]ù  }|j                  d«      }|r~|j                  d«      xs g D �cg c]J  }|j                  d«      dk(  r4d|j                  d«      |j                  d«      |j                  d«      dœ‘ŒL }}|r|j                  d|d	œ«       |j                  d
«      }|rŽ|j                  d«      xs g D �	cg c]Z  }	|	j                  d«      dk(  rDd|	j                  d«      |	j                  d«      |	j                  d«      |	j                  d«      dœ‘Œ\ }
}	|
r|j                  d
|
d	œ«       |j                  d«      }|rìg }|j                  d«      xs g D ]J  }|j                  d«      dk(  sŒ|j                  d|j                  d«      |j                  d«      dœ«       ŒL |j                  d«      xs g D ]Z  }|j                  d«      dk(  sŒ|j                  d|j                  d«      |j                  d«      |j                  d«      dœ«       Œ\ |r|j                  d|d	œ«       |j                  d«      }|�rg }|j                  d«      xs g D ]Z  }|j                  d«      dk(  sŒ|j                  d|j                  d«      |j                  d«      |j                  d«      dœ«       Œ\ |j                  d«      xs g D ]j  }|j                  d«      dk(  sŒ|j                  d|j                  d«      |j                  d«      |j                  d«      |j                  d«      dœ«       Œl |r|j                  d|d	œ«       |j                  d«      }|s�Œj|j                  d«      xs g D �	cg c]Z  }	|	j                  d«      dk(  rDd|	j                  d«      |	j                  d«      |	j                  d«      |	j                  d«      dœ‘Œ\ }}	|s�Œæ|j                  d|d	œ«       �Œü |S c c}w c c}	w c c}	w )aö  
        Walk the Bedrock guardrail response and emit a structured list of
        BLOCKED assessment entries describing exactly which policies fired.

        Mirrors the iteration in `_should_raise_guardrail_blocked_exception()`
        but produces a list of `{policy, matches}` dicts instead of a bool.
        Each `match` carries the originating subcategory, type, action, and
        matched term where available, so the client can render a precise
        explanation of the violation.
        r‹   ÚtopicPolicyÚtopicsr  ÚBLOCKEDr�  ræ   )rP  r�  ræ   r  )ÚpolicyrŒ  ÚcontentPolicyÚfiltersÚ
confidenceÚfilterStrength)rP  ræ   r˜  r™  r  Ú
wordPolicyÚcustomWordsr�  )rP  r�  r  ÚmanagedWordLists)rP  ræ   r�  r  ÚsensitiveInformationPolicyÚpiiEntitiesÚregexesÚregex)rP  r�  r   r�  r  ÚcontextualGroundingPolicyrZ  r]  )rP  ræ   rZ  r]  r  )r¢   rÌ   )r®   rz   Úblockedr‹   r  Útopic_policyÚtÚtopic_matchesÚcontent_policyÚfÚcontent_matchesÚword_policyÚword_matchesÚwÚmwÚsensitive_infoÚpii_matchesÚpÚrÚ
contextualÚgrounding_matchess                        rp   rŽ  z-BedrockGuardrail._extract_blocked_assessmentsq  s  € ð &(ˆØ%Ÿ\™\¨-¸Ó<ÒBÀˆà%ó q	ˆJà%Ÿ>™>¨-Ó8ˆLÙð +×.Ñ.¨xÓ8Ò>¸Bö	!ð Ø—u‘u˜X“¨)Ò3ð %-Ø !§¡ f£Ø !§¡ f£Ø"#§%¡%¨£/ó	ð	!�ð 	!ñ !Ø—N‘N¨mÈÑ#VÔWð (Ÿ^™^¨OÓ<ˆNÙð -×0Ñ0°Ó;ÒA¸rö
#ð Ø—u‘u˜X“¨)Ò3ð %.Ø !§¡ f£Ø&'§e¡e¨LÓ&9Ø*+¯%©%Ð0@Ó*AØ"#§%¡%¨£/óð
#�ð 
#ñ #Ø—N‘N¨oÈ/Ñ#ZÔ[ð %Ÿ.™.¨Ó6ˆKÙØ+-�Ø$Ÿ™¨Ó7Ò=¸2ò �AØ—u‘u˜X“¨)Ó3Ø$×+Ñ+à,9Ø)*¯©¨w«Ø*+¯%©%°«/ñõðð &Ÿ/™/Ð*<Ó=ÒCÀò 	�BØ—v‘v˜hÓ'¨9Ó4Ø$×+Ñ+à,>Ø(*¯©¨v«Ø)+¯©°«Ø*,¯&©&°Ó*:ñ	õð	ñ  Ø—N‘N¨lÀ|Ñ#TÔUð (Ÿ^™^Ð,HÓIˆNÚØ*,�Ø'×+Ñ+¨MÓ:Ò@¸bò 	�AØ—u‘u˜X“¨)Ó3Ø#×*Ñ*à,9Ø()¯©¨f«Ø)*¯©¨w«Ø*+¯%©%°«/ñ	õð	ð (×+Ñ+¨IÓ6Ò<¸"ò 
�AØ—u‘u˜X“¨)Ó3Ø#×*Ñ*à,5Ø()¯©¨f«Ø)*¯©¨w«Ø)*¯©¨w«Ø*+¯%©%°«/ñõð
ñ Ø—N‘Nà&BØ'2ñôð $Ÿ™Ð(CÓDˆJÛð )Ÿn™n¨YÓ7Ò=¸2ö
%ð Ø—u‘u˜X“¨)Ò3ð %.Ø !§¡ f£Ø%&§U¡U¨;Ó%7Ø!"§¡ w£Ø"#§%¡%¨£/óð
%Ð!ð 
%ó %Ø—N‘Nà&AØ'8ñöðYq	ðf ˆùò_	!ùò 
#ùòX
%s   Á	APÃAPÎAP$c                 óä  — d}|j                  dg «      xs g }|r1|D ],  }|j                  d«      sŒ||j                  d«      xs dz  }Œ. | j                  du r/|xs i }t        ||j                  dd«      || j                  ¬«      S d|d	œ}| j                  r| j                  |d
<   | j
                  r| j
                  |d<   | j                  |«      }|rt        |«      |d<   t        d|¬«      S )zA
        Get the HTTP exception for a blocked guardrail.
        rç   r	  rf   Trr  rs  rt  rq  )r¤  r¦  r‘   r’   r‹   ru  r’  )	r¢   r“   r   rn  r‘   r’   rŽ  r�   r   )	r®   rz   r  Úbedrock_guardrail_output_textr	  r
  rw  rh  r‹   s	            rp   r¢  z:BedrockGuardrail._get_http_exception_for_blocked_guardrailô  s  € ð .0Ð%Ø>F¿l¹lÈ9ÐVXÓ>YÒ>_Ð]_ˆÙØ!ò N�Ø—:‘:˜fÕ%Ø1°V·Z±ZÀÓ5GÒ5MÈ2ÑMÑ1ðNð ×*Ñ*¨dÑ2Ø#/Ò#5°2ˆMÜ*Ø5Ø#×'Ñ'¨Ð1DÓEØ*Ø#×2Ñ2ô	ð ð 1Ø*Gñ)
ˆð ×#Ò#Ø,0×,DÑ,DˆFÐ(Ñ)Ø× Ò Ø)-×)>Ñ)>ˆFÐ%Ñ&à!×>Ñ>¸xÓHˆÙÜ$CÀKÓ$PˆF�=Ñ!ä¨°VÔ<Ð<ro   c                 ó  — |j                  d«      dk7  ry|j                  d«      xs g }|sy|D �]Í  }|j                  d«      }|r3|j                  d«      xs g }|D ]  }|j                  d«      dk(  sŒ  y |j                  d	«      }|r3|j                  d
«      xs g }|D ]  }	|	j                  d«      dk(  sŒ  y |j                  d«      }
|
rf|
j                  d«      xs g }|D ]  }|j                  d«      dk(  sŒ  y |
j                  d«      xs g }|D ]  }|j                  d«      dk(  sŒ  y |j                  d«      }|rj|j                  d«      xs g }|r|D ]  }|j                  d«      dk(  sŒ  y |j                  d«      xs g }|r|D ]  }|j                  d«      dk(  sŒ  y |j                  d«      }|s�Œ›|j                  d
«      xs g }|D ]  }|j                  d«      dk(  sŒ  y �ŒÐ y)a¹  
        Only raise exception for "BLOCKED" actions, not for "ANONYMIZED" actions.

        If `self.mask_request_content` or `self.mask_response_content` is set to `True`,
        then use the output from the guardrail to mask the request or response content.

        However, even with masking enabled, content with action="BLOCKED" should still
        raise an exception, only content with action="ANONYMIZED" should be masked.
        r  r  Fr‹   r’  r“  r”  Tr–  r—  rš  r›  rœ  r�  rž  rŸ  r¡  rÄ  )r®   rz   r‹   r  r£  r“  Útopicr¦  r—  Úfilter_itemr©  Úcustom_wordsÚcustom_wordÚmanaged_wordsÚmanaged_wordÚsensitive_info_policyÚpii_entitiesÚ
pii_entityrŸ  r   Úcontextual_grounding_policyÚgrounding_filtersÚgrounding_filters                          rp   r   z:BedrockGuardrail._should_raise_guardrail_blocked_exception	  sA  € ð �<‰<˜Ó!Ð%;Ò;Øð
 &Ÿ\™\¨-Ó8Ò>¸BˆÙØà%ó 1	$ˆJà%Ÿ>™>¨-Ó8ˆLÙØ%×)Ñ)¨(Ó3Ò9°r�Ø#ò $�EØ—y‘y Ó*¨iÓ7Ú#ð$ð
 (Ÿ^™^¨OÓ<ˆNÙØ(×,Ñ,¨YÓ7Ò=¸2�Ø#*ò $�KØ"—‘ xÓ0°IÓ=Ú#ð$ð
 %Ÿ.™.¨Ó6ˆKÙØ*Ÿ™¨}Ó=ÒCÀ�Ø#/ò $�KØ"—‘ xÓ0°IÓ=Ú#ð$ð !,§¡Ð0BÓ CÒ IÀr�Ø$1ò $�LØ#×'Ñ'¨Ó1°YÓ>Ú#ð$ð
 %/§N¡NÐ3OÓ$PÐ!Ù$Ø4×8Ñ8¸ÓGÒMÈ2�ÙØ&2ò (˜
Ø%Ÿ>™>¨(Ó3°yÓ@Ú#'ð(ð 0×3Ñ3°IÓ>ÒDÀ"�ÙØ!(ò (˜Ø Ÿ9™9 XÓ.°)Ó;Ú#'ð(ð
 +5¯.©.Ð9TÓ*UÐ'Û*Ø$?×$CÑ$CÀIÓ$NÒ$TÐRTÐ!Ø(9ò $Ð$Ø'×+Ñ+¨HÓ5¸ÓBÚ#ò$ð_1	$ðj ro   Úuser_api_key_dictÚcacheÚ	call_typec              ƒ   ó|  K  — t        j                  d|«       ddlm} t        j
                  }| j                  ||¬«      dur|S | j                  t        t        |«      |¬«      }|€t        j                  d«       |S | j                  |¬«      }|j                  }	|	st        j                  d	«       |S | j                  d
|	|t        j
                  ¬«      ƒ d {  –—† }
| j                  |	|
¬«      }| j                  |j                  xs |||j                   ¬«      |d<    ||| j"                  ¬«       |S 7 Œ\­w)Nz.Inside Bedrock Pre-Call Hook for call_type: %sr   ©Ú*add_guardrail_to_applied_guardrails_header©r;  rd  T©rÄ  r;  z3No messages found for call_type, skipping guardrailrã   z5No user-role messages available for guardrail payloadrÆ   ©rJ   rÄ   r  rZ  ©rÄ   r¦  ©rt   r!  ru   rÄ   ©r  rn  )r   r¬   Ú)litellm.proxy.common_utils.callback_utilsrÇ  r+   r³   Úshould_run_guardrailÚ%get_guardrails_messages_for_call_typer   r=   r÷   rs   r^  Ú8_update_messages_with_updated_bedrock_guardrail_responser'  rt   ru   rn  )r®   rÂ  rÃ  r;  rÄ  rÇ  rd  Únew_messagesr  r   r¦  Úupdated_subsets               rp   Úasync_pre_call_hookz$BedrockGuardrail.async_pre_call_hookf	  sa  è ø€ ô 	×"Ñ"Ð#SÐU^Ô_õ	
ô 2E×1MÑ1Mˆ
Ø×$Ñ$¨$¸:Ð$ÓFÈdÑRØˆKà"×HÑHÜœ9 iÓ0Øð Ió 
ˆð ÐÜ ×&Ñ&Ð'\Ô]ØˆKà#×HÑHÐR^ÐHÓ_ˆà#0×#AÑ#AÐÙ Ü ×&Ñ&Ð'^Ô_ØˆKð 37×2OÑ2OØØ&ØÜ2×;Ñ;ð	 3Pó 3
÷ -
Ð"ð !%× ]Ñ ]Ø&Ø'Að !^ó !
ˆð  ×8Ñ8Ø+×=Ñ=ÒMÀØ$2Ø(×7Ñ7ð 9ó 
ˆˆZÑñ 	3ÀÐUY×UhÑUhÕiØˆð3-
ús   ‚CD<ÃD:ÃAD<c              ƒ   óˆ  K  — ddl m} t        j                  }|t        j
                  j                  k(  rt        j                  }| j                  ||¬«      dury | j                  t        t        |«      |¬«      }|€t        j                  d«       y | j                  |¬«      }|j                  }|st        j                  d«       y | j!                  d	|||¬
«      ƒ d {  –—† }	| j#                  ||	¬«      }
| j%                  |j&                  xs ||
|j(                  ¬«      |d<    ||| j*                  ¬«       |S 7 Œ\­w)Nr   rÆ  rÈ  TrÉ  ú6Bedrock AI: not running guardrail. No messages in datarã   z8Bedrock AI: not running guardrail. No user-role messagesrÆ   rÊ  rË  rÌ  rÄ   rÍ  )rÎ  rÇ  r+   rµ   r=   Úcall_mcp_toolrÂ   r·   rÏ  rÐ  r   r   r«   r÷   rs   r¬   r^  rÑ  r'  rt   ru   rn  )r®   r;  rÂ  rÄ  rÇ  rd  rÒ  r  r   r¦  rÓ  s              rp   Úasync_moderation_hookz&BedrockGuardrail.async_moderation_hook©	  s_  è ø€ õ	
ô +>×*IÑ*Iˆ
Øœ	×/Ñ/×5Ñ5Ò5Ü,×<Ñ<ˆJØ×$Ñ$¨$¸:Ð$ÓFÈdÑRØà"×HÑHÜœ9 iÓ0Øð Ió 
ˆð
 ÐÜ ×(Ñ(Ð)aÔbØà#×HÑHÐR^ÐHÓ_ˆØ#0×#AÑ#AÐÙ Ü ×&Ñ&Ð'aÔbØð 37×2OÑ2OØØ&ØØ)ð	 3Pó 3
÷ -
Ð"ð !%× ]Ñ ]Ø&Ø'Að !^ó !
ˆð  ×8Ñ8Ø+×=Ñ=ÒMÀØ$2Ø(×7Ñ7ð 9ó 
ˆˆZÑñ 	3ÀÐUY×UhÑUhÕiàˆð5-
ús   ‚C!EÃ#E Ã$AEc              ƒ   óæ  K  — ddl m} ddlm} | j	                  ||j
                  ¬«      dury |j                  d«      }|€t        j                  d«       y t        |t        j                  «      r…d}|j                  D ]\  }t        |t        j                  «      sŒ|j                  j                  sŒ5t        |j                  j                  t         «      sŒZd} n |st        j                  d	«       y 	 | j#                  d
||||j
                  ¬«      ƒ d {  –—† }	|	�| j)                  ||	¬«        ||| j*                  ¬«       y 7 Œ.# t$        $ r}
|
j&                  €||
_        ‚ d }
~
ww xY w­w)Nr   rÆ  )r+   rÈ  TrÄ   rÖ  Fz=Bedrock AI: not running guardrail. No output text in responserÓ   ©rJ   rz   rÄ   r  rZ  ©rz   r¦  rÍ  )rÎ  rÇ  Úlitellm.types.guardrailsr+   rÏ  r´   r¢   r   r«   r‡   rß   rC   rà   r?   rÉ   rI   rl   r^  r   Úoriginal_responseÚ_apply_masking_to_responsern  )r®   r;  rÂ  rz   rÇ  r+   rÒ  Úhas_text_contentrá   Úoutput_content_bedrockr:  s              rp   Úasync_post_call_success_hookz-BedrockGuardrail.async_post_call_success_hookî	  sm  è ø€ õ	
õ 	Aà×$Ñ$¨$Ð;N×;XÑ;XÐ$ÓYÐaeÑeØà=A¿X¹XÀjÓ=QˆØÐÜ ×(Ñ(Ð)aÔbØô �h¤× 5Ñ 5Ô6Ø$ÐØ"×*Ñ*ò �Ü˜f¤g§o¡oÕ6Ø—~‘~×-Ó-´*¸V¿^¹^×=SÑ=SÔUXÕ2YØ+/Ð(Ùð	ñ $Ü$×,Ñ,Ð-lÔmØð	Ø26×2OÑ2OØØ!Ø%Ø!Ø#6×#@Ñ#@ð 3Pó 3÷ -Ð"ð "Ð-Ø×+Ñ+Ø!Ø+Að ,ô ñ 	3ÀÐUY×UhÑUhÖið1-ùô 'ò 	Ø×"Ñ"Ð*Ø&.�Ô#Øûð	üsN   ‚BE1ÂE1Â5$E1ÃE1Ã8#E ÄE
ÄE Ä *E1Å
E Å	E.ÅE)Å)E.Å.E1r¦  c                 óÖ   — | j                  |«      }|r(t        j                  d«       | j                  ||¬«      S | j                  s| j
                  rt        j                  d«       |S )af  
        Use the output from the bedrock guardrail to mask sensitive content in messages.

        Args:
            messages: Original list of messages
            bedrock_guardrail_response: Response from Bedrock guardrail containing masked content

        Returns:
            List of messages with content masked according to guardrail response
        z>Bedrock guardrail provided masked output, applying to messages)rÄ   r  zPMasking enabled but no masked output from guardrail, returning original messages)Ú#_extract_masked_texts_from_responser   r¬   Ú_apply_masking_to_messagesr�   rž   )r®   rÄ   r¦  r  s       rp   rÑ  zIBedrockGuardrail._update_messages_with_updated_bedrock_guardrail_response:
  sk   € ð  #×FÑFÐGaÓbˆñ Ü ×&Ñ&Ð'gÔhØ×2Ñ2¸HÐS_Ð2Ó`Ð`ð ×$Ò$¨×(BÒ(BÜ ×&Ñ&Øbôð ˆro   c           
     ó˜  K  — ddl m} ddlm} ddlm} t        j                  «       }g }|2 3 d{  –—† }	|j                  |	«       Œ7 Œ6 t        |«      }
|
rt        |d¬«      n ||¬«      }t        |t        «      �rt        |«      }|}	 | j                  d	||j                  d
«      |t         j"                  ¬«      ƒ d{  –—†7  }�ns# t$        $ r§}|j&                  }|
xr! |j(                  dk(  xr t        |t*        «      }t-        t        j                  «       |z
  t.        j0                  «      }|
r|s|s‚ t3        |«      \  }}t5        |r|n|j(                  › d|› �«      D ]  }|­–— Œ	 Y d}~yd}~wt6        $ r¹}|
r\|j8                  xs |j8                  |_        |j:                  €||_        t=        «       j?                  |d¬«      D ]  }|­–— Œ	 Y d}~ytA        |dd«      }t        tC        dtE        d|jF                  ¬«      d¬«      g|j8                  ¬«      }|�||_$        d}Y d}~nd}~ww xY w|�| jK                  ||¬«       |
r&t        |«      |k7  rtM        |«      n|D ]  }|­–— Œ	 y ||¬«      }|2 3 d{  –—†7  }	|	­–— Œ6 y|
r#t5        | jN                  › d�«      D ]  }|­–— Œ	 y|D ]  }	|	­–— Œ	 y­w)z®
        Process streaming response chunks.

        Collect content from the stream and run the bedrock OUTPUT scan
        (post_call only validates the response).
        r   )ÚMockResponseIterator)Ústream_chunk_builder)ÚTextCompletionResponseNT)Úrestore_identity)ÚchunksrÓ   rÄ   rÚ  ru  z: F)Ústream_startedrž  r<  r  Úcontent_filter©rü   rÉ   Úfinish_reason)rà   rr  rÛ  )Úmodel_responsezD: streamed response could not be assembled for scanning, blocking it)(Ú)litellm.llms.base_llm.base_model_iteratorræ  Úlitellm.mainrç  Úlitellm.types.utilsrè  ÚtimeÚ	monotonicrÌ   r'   r&   r‡   rC   r(   r^  r¢   r+   r´   r   rh  r“  r   r#   rß   Ú#anthropic_sse_ping_interval_secondsr"   r%   r   rr  rÝ  r   Úbuild_block_sse_chunksrª   r?   rB   rÉ   rž  rÞ  r$   rn  )r®   rÂ  rz   r  ræ  rç  rè  Ú
started_atÚ
all_chunksÚchunkÚraw_sseÚassembled_model_responseÚpre_guardrail_textÚ_pre_block_responseÚoutput_guardrail_responseÚ	block_excÚblock_detailÚis_blockÚheaders_flushedÚblock_messagerS  Úerror_framer:  Úblock_chunkÚ_original_usageÚ	sse_chunkÚmock_responses                              rp   Ú'async_post_call_streaming_iterator_hookz8BedrockGuardrail.async_post_call_streaming_iterator_hook[
  s!  è ø€ õ 	SÝ5Ý>ô !ŸN™NÓ,ˆ
Ø79ˆ
Ø#÷ 	%ð 	%�%Ø×Ñ˜eÕ$ð	%ø˜8ô +¨:Ó6ˆñ ô *¨*ÀtÕLá%¨ZÔ8ð 	!ô
 Ð.´Õ>Ü(;Ð<TÓ(UÐØ)AÐð 41Ø26×2OÑ2OØ#Ø5Ø)×-Ñ-¨jÓ9Ø!-Ü':×'DÑ'Dð 3Pó 3÷ -ð -Ò)øô !ò Ø&/×&6Ñ&6�ð
 #*Ò"p¨i×.CÑ.CÀsÑ.JÒ"pÌzÐZfÔhoÓOp�Ü)AÜ—N‘NÓ$ zÑ1´7×3^Ñ3^ó*�ñ ¡x¹ØÜ#CÀLÓ#QÑ �˜qÜ#=Ù%-‘M°i×6KÑ6KÐ5LÈBÈ}ÈoÐ3^ó$ò &�Kð &Ô%ð&ô ûÜ*ò 1ÙØ1×7Ñ7ÒB¸1¿7¹7�A”GØ×*Ñ*Ð2Ø.A˜Ô+Ü'?Ó'A×'XÑ'XÐYZÐkpÐ'XÓ'qò *˜Ø)Ô)ð*äô *1Ð1IÈ7ÐTXÓ)Y�Ü+8äØ"#Ü$+°ÀaÇiÁiÔ$PØ*:ôðð Ÿ'™'ô	,Ð(ð #Ð.Ø5DÐ,Ô2Ø,0Õ)ûð51úð> )Ð4Ø×/Ñ/Ø5Ø/Hð 0ô ñ ô +Ð+CÓDÐHZÒZô 7Ð7OÔPà#ò$�Ið
 $”Oð$ð á#7ÐG_Ô#`ˆMð  -÷ ñ �eØ”ñ  -áô  :Ø×&Ñ&Ð'Ð'kÐló ò "�ð "Ô!ð"ð à#ò �Ø”ñùs–   ‚+K
­A
±A²A
µK
ÁA
Á
AK
Â6C ÃCÃC Ã	K
Ã	H;ÃBE6Å1K
Å6H;ÆAH6ÇK
Ç AH6È1K
È6H;È;AK
ÊJÊ
JÊJÊ;K
c                 óÀ   — g }|j                  dg «      xs g }|st        j                  d«       g S |D ]'  }|j                  d«      }|€Œ|j                  |«       Œ) |S )zß
        Extract all masked text outputs from the guardrail response.

        Args:
            bedrock_guardrail_response: Response from Bedrock guardrail

        Returns:
            List of masked text strings
        r	  z-No masked outputs found in guardrail responserf   )r¢   r   r¬   rÌ   )r®   r¦  Úmasked_output_textÚmasked_outputsr
  rë   s         rp   rã  z4BedrockGuardrail._extract_masked_texts_from_responseè
  st   € ð 02ÐØE_×EcÑEcÐdmÐoqÓErÒExÐvxˆÙÜ ×&Ñ&Ð'VÔWØˆIà$ò 	8ˆFØ'-§z¡z°&Ó'9ˆLØÑ'Ø"×)Ñ)¨,Õ7ð	8ð
 "Ð!ro   c                 óT  — g }d}|D ]ž  }|j                  «       }|j                  d«      }|€|j                  |«       Œ8t        |t        «      r|t        |«      k  r8||   |d<   |dz  }n*t        |t        «      r| j                  |||¬«      \  |d<   }|j                  |«       Œ  |S )a  
        Apply masked texts to message content using index tracking.

        Args:
            messages: Original messages
            masked_texts: List of masked text strings from guardrail

        Returns:
            Updated messages with masked content
        r   rI   rù   )Úcontent_listr  Úmasking_index)r`  r¢   rÌ   r‡   rl   r×   rv   Ú_mask_content_list)r®   rÄ   r  Úupdated_messagesr  rÉ   Únew_messagerI   s           rp   rä  z+BedrockGuardrail._apply_masking_to_messagesÿ
  sÌ   € ð #%ÐØˆàò 	1ˆGØ!Ÿ,™,›.ˆKØ!—o‘o iÓ0ˆGð ˆØ ×'Ñ'¨Ô4Øô ˜'¤3Ô'Ø ¤3 |Ó#4Ò4Ø-9¸-Ñ-H�K 	Ñ*Ø! QÑ&‘Mä˜G¤TÔ*Ø8<×8OÑ8OØ!(Ø!-Ø"/ð 9Pó 9Ñ5�˜IÑ&¨ð ×#Ñ# KÕ0ð-	1ð0  Ðro   r  r  c                 ó8  — g }|D ]�  }t        |t        «      rAd|v r=|j                  «       }|t        |«      k  r||   |d<   |dz  }|j	                  |«       ŒTt        |t
        «      sŒe|t        |«      k  r
||   }|dz  }|€Œ€|j	                  |«       Œ’ ||fS )a9  
        Apply masking to a list of content items.

        Args:
            content_list: List of content items
            masked_texts: List of masked text strings
            starting_index: Starting index in the masked_texts list

        Returns:
            Updated content list with masked items
        rf   rù   )r‡   rˆ   r`  r×   rÌ   rl   )r®   r  r  r  Únew_contentrè   Únew_items          rp   r  z#BedrockGuardrail._mask_content_list)  s³   € ð 02ˆØ ò 	-ˆDÜ˜$¤Ô%¨&°D©.ØŸ9™9›;�Ø ¤3 |Ó#4Ò4Ø'3°MÑ'B�H˜VÑ$Ø! QÑ&�MØ×"Ñ" 8Õ,Ü˜D¤#Õ&Ø ¤3 |Ó#4Ò4Ø'¨Ñ6�DØ! QÑ&�MØÑ#Ø×&Ñ& tÕ,ð	-ð ˜MÐ)Ð)ro   c                 ó,  — | j                  |«      }|st        j                  d«       yt        j                  dt        |«      «       t	        |t
        j                  «      r| j                  ||«       yt        j                  dt        |«      «       y)zú
        Apply masked content from bedrock guardrail to the response object.

        Args:
            response: The response object to modify
            bedrock_guardrail_response: Response from Bedrock guardrail containing masked content
        z2No masked outputs found, skipping response maskingNz1Applying masking to response with %d masked textsz)Unsupported response type for masking: %s)
rã  r   r¬   r×   r‡   rß   rC   Ú _apply_masking_to_model_responser«   ræ   )r®   rz   r¦  r  s       rp   rÞ  z+BedrockGuardrail._apply_masking_to_responseH  s|   € ð #×FÑFÐGaÓbˆáÜ ×&Ñ&Ð'[Ô\Øä×"Ñ"Ð#VÔX[Ð\hÓXiÔjô �h¤× 5Ñ 5Ô6Ø×1Ñ1°(¸LÕIä ×(Ñ(Ð)TÔVZÐ[cÓVdÕero   c                 ó8  — d}|j                   D �]ˆ  }t        |t        «      rz|j                  j                  sŒ+t        |j                  j                  t
        «      sŒP|t        |«      k  sŒ_||   |j                  _        |dz  }t        j                  d«       ŒŽt        |t        «      r{|j                  j                  sŒµt        |j                  j                  t
        «      sŒÚ|t        |«      k  sŒé||   |j                  _        |dz  }t        j                  d«       �Œt        |t        «      s�Œ+|j                  s�Œ9t        |j                  t
        «      s�ŒU|t        |«      k  s�Œe||   |_        |dz  }t        j                  d«       �Œ‹ y)zÕ
        Apply masked texts to a ModelResponse object.

        Args:
            response: The ModelResponse object to modify in-place
            masked_texts: List of masked text strings from guardrail
        r   rù   z)Applied masking to choice message contentz'Applied masking to choice delta contentz&Applied masking to choice text contentN)rà   r‡   r?   rÉ   rI   rl   r×   r   r¬   rE   ÚdeltarF   rf   )r®   rz   r  r  rá   s        rp   r  z1BedrockGuardrail._apply_masking_to_model_responsec  s4  € ð ˆà×&Ñ&ó 	]ˆFÜ˜&¤'Ô*à—>‘>×)Ó)¬j¸¿¹×9OÑ9OÔQTÕ.UØ$¤s¨<Ó'8Ó8Ø1=¸mÑ1L˜Ÿ™Ô.Ø%¨Ñ*˜Ü,×2Ñ2Ð3^Õ_Ü˜FÔ$4Ô5à—<‘<×'Ó'¬J°v·|±|×7KÑ7KÌSÕ,QØ$¤s¨<Ó'8Ó8Ø/;¸MÑ/J˜Ÿ™Ô,Ø%¨Ñ*˜Ü,×2Ñ2Ð3\Ö]Ü˜F¤KÖ0à—;”;¤:¨f¯k©k¼3Ö#?Ø$¤s¨<Ó'8Ô8Ø&2°=Ñ&A˜œØ%¨Ñ*˜Ü,×2Ñ2Ð3[Ö\ñ+	]ro   c                  ór   — ddl m}  	 ddlm} |�|j
                  j                  S | S # t        $ r | cY S w xY w)a¶  Resolve the cache used to remember which segments a session already scanned.

        Prefers the proxy's shared cache (``internal_usage_cache.dual_cache``), which is
        backed by Redis when the deployment configures it, so incremental state is shared
        across proxy instances. Falls back to a process-local ``DualCache`` singleton when
        the proxy is not running (e.g. unit tests), where sharing does not apply.
        r   )Údc)Úproxy_logging_obj)Ú%litellm.integrations.custom_guardrailr  Úlitellm.proxy.proxy_serverr  r»  Úinternal_usage_cacheÚ
dual_cache)Úfallback_cacheÚ_proxy_loggings     rp   Ú_incremental_scan_cachez(BedrockGuardrail._incremental_scan_cache„  sG   € õ 	Oð	"ÝVð Ð%Ø!×6Ñ6×AÑAÐAØÐøô	 ò 	"Ø!Ò!ð	"ús   ˆ( ¨6µ6c                 ód   — dD ]+  }|j                  |«      xs g }t        d„ |D «       «      sŒ+ y y)zðReturn True if the guardrail rewrote (masked/anonymized) any scanned text.

        Bedrock returns non-empty ``output``/``outputs`` text only when it changed the
        content; an ``action == "NONE"`` response leaves both empty.
        )r
  r	  c              3   ób   K  — | ]'  }t        |t        «      xr |j                  d «      –— Œ) y­w)rf   Nrÿ   r   s     rp   r  zGBedrockGuardrail._bedrock_response_has_masked_output.<locals>.<genexpr>Ÿ  s(   è ø€ ÒQÀ4”:˜d¤DÓ)Ò>¨d¯h©h°vÓ.>Ó>ÑQùs   ‚-/TF)r¢   rù  )r®   rz   Úfieldr¾   s       rp   Ú#_bedrock_response_has_masked_outputz4BedrockGuardrail._bedrock_response_has_masked_output—  s<   € ð +ò 	ˆEØ—L‘L Ó'Ò-¨2ˆEÜÑQÈ5ÔQÕQÙð	ð ro   c           
   ƒ   óØ  K  — | j                  «       }| j                  |||¬«      ƒ d{  –—† }|€y|st        j                  d«       |S | j	                  d|D �cg c]  }t        d|¬«      ‘Œ c}|t        j                  ¬«      ƒ d{  –—† }| j                  |«      r!t        j                  d| j                  «       y| j                  |||¬«      ƒ d{  –—†  |S 7 Œ´c c}w 7 Œ[7 Œ­w)	a¤  Scan only the text segments not already seen earlier in this session.

        Returns ``None`` when incremental scanning is inactive (feature off, no
        session id, masking enabled, or cache unavailable) or when the guardrail
        turns out to mask content, telling the caller to run the normal full scan.
        Otherwise scans only the new segments and skips the Bedrock call entirely
        when nothing is new. Incremental mode is for blocking/detection guardrails
        only: if the guardrail returns masked output it cannot be applied to the
        skipped context, so the scan falls back to the full path and no session
        state is recorded.
        )r  r  rÃ  NzNBedrock Guardrail: no new messages to scan for this session, skipping API callrÆ   rò   r  rÊ  z§Bedrock Guardrail %s: guardrail returned masked/anonymized content; only_scan_new_messages cannot apply masking to skipped context, falling back to a full-context scan)r#  Úfilter_new_texts_for_sessionr   r¬   r^  r-   r+   r³   r'  r«   rn  Úmark_texts_scanned)r®   r  r  r  rÃ  Ú	new_textsrf   Úbedrock_responses           rp   Ú_apply_incremental_request_scanz0BedrockGuardrail._apply_incremental_request_scan£  s  è ø€ ð" ×3Ñ3Ó5ˆà!%×!BÑ!BØØ%Øð "Có "
÷ 
ˆ	ð
 ÐØáÜ ×&Ñ&Ð'wÔxØˆMà(,×(EÑ(EØØW`ÖaÈtÔ/°VÀTÖJÒaØ%Ü2×;Ñ;ð	 )Fó )
÷ #
Ðð ×3Ñ3Ð4DÔEÜ ×(Ñ(ðvà×#Ñ#ôð
 à×%Ñ%ØØ%Øð &ó 
÷ 	
ð 	
ð
 ˆðA
úò bð#
øð	
ús@   ‚(C*ªC«0C*ÁC!
Á/C*Â
C&ÂAC*ÃC(ÃC*Ã!C*Ã(C*Úlogging_objÚLiteLLMLoggingObjc              ƒ   ó(  K  — |j                  d«      xs g }	 t        j                  dt        |«      «       |dk(  r | j	                  |||¬«      ƒ d{  –—† }|�|S g }| j                  ||||¬«      }|j                  r|S |j                  }	|j                  }
|j                  }|	�r^|dk(  rt        j                  nt        j                  }|dk(  rdnd	}|dk(  ryt        t        |	«      D ��cg c]:  \  }}t        |t!        d
t#        |j                  d«      xs d«      ¬«      d¬«      ‘Œ< c}}¬«      }| j%                  d|||¬«      ƒ d{  –—† }n| j%                  d	|	||¬«      ƒ d{  –—† }|j                  d«      }|r8|D ]2  }|j                  d«      }|sŒt#        |«      }|j'                  |«       Œ4 nJ|j                  d«      }|r7|D ]2  }|j                  d«      }|sŒt#        |«      }|j'                  |«       Œ4 | j)                  |||
|¬«      }t        j                  d«       ||d<   |S 7 �Œäc c}}w 7 Œñ7 ŒÕ# t*        t,        f$ r ‚ t.        $ r2}t        j0                  dt#        |«      «       t/        d|› �«      ‚d}~ww xY w­w)aÁ  
        Apply Bedrock guardrail to a batch of texts for testing purposes.

        This method allows users to test Bedrock guardrails without making actual LLM calls.
        It creates mock messages to test the guardrail functionality.

        Args:
            inputs: Dictionary containing texts and optional images
            request_data: Request data dictionary for logging metadata
            input_type: Whether this is a "request" or "response"
            logging_obj: Optional logging object

        Returns:
            GenericGuardrailAPIInputs - processed_texts may be masked, images unchanged

        Raises:
            Exception: If content is blocked by Bedrock guardrail
        r  z3Bedrock Guardrail: Applying guardrail to %s text(s)r  )r  r  r  N)r  r  r  r  rz   rÓ   rÆ   r<  rI   rç   r  Ústoprí  )rà   )rJ   rz   r  rZ  rÊ  r
  rf   r	  )r  r  r€   r�   z1Bedrock Guardrail: Successfully applied guardrailz0Bedrock Guardrail: Failed to apply guardrail: %szBedrock guardrail failed: )r¢   r   r¬   r×   r-  r  r‚   r   r€   r�   r+   r³   r´   rC   r	  r?   rB   rl   r^  rÌ   r   r   r   r»  r¤  )r®   r  r  r  r.  r  Úincremental_resultr  Ú	selectionr   r€   r�   Ú	_log_hookÚbedrock_sourceÚ_idxÚ_msgÚsynthetic_responser,  Úoutput_listÚoutput_itemrë   r  Úoutputs_listr:  s                           rp   Úapply_guardrailz BedrockGuardrail.apply_guardrailØ  s  è ø€ ð6 —z‘z 'Ó*Ò0¨bˆðn	>Ü ×&Ñ&Ð'\Ô^aÐbgÓ^hÔià˜YÒ&Ø26×2VÑ2VØØ!Ø!-ð 3Wó 3÷ -Ð"ð
 &Ð1Ø-Ð-àˆLà#×HÑHØØØ)Ø%ð	  Ió  ˆIð ×"Ò"Ø�Ø'0×'BÑ'BÐØ#,×#:Ñ#:ˆMØ)2×)FÑ)FÐò !Ø<FÈ)Ò<SÔ/×8Ò8ÔYl×YvÑYv�	ð Q[Ð^hÒPhÁHÐnu�Ø! XÒ-ô 1>ô /8Ð8IÓ.J÷
!ñ !+  dô $Ø&*Ü(/Ø)4Ü,/°·±¸Ó0CÒ0IÀrÓ,Jô)"ð /5öó
!ô1Ð&ð .2×-JÑ-JØ'Ø!3Ø%1Ø+4ð	 .Kó .÷ (Ñ$ð .2×-JÑ-JØ&Ø!2Ø%1Ø+4ð	 .Kó .÷ (Ð$ð &6×%9Ñ%9¸(Ó%C�Ùà'2ò =˜Ø'2§¡°vÓ'>˜Ú'Ü*-¨lÓ*;˜KØ(×/Ñ/°Õ<ñ	=ð +;×*>Ñ*>¸yÓ*I�LÙ#à+7ò A˜KØ+6¯?©?¸6Ó+B˜LÚ+Ü.1°,Ó.? Ø ,× 3Ñ 3°KÕ @ð	Að  ×3Ñ3Ø)ØØ+Ø$7ð	 4ó ˆLô !×&Ñ&Ð'ZÔ[à*ˆF�7‰OØˆMð}-ûóJ
!ð(øð(ùôP Ô6Ð7ò 	ð Üò 	>Ü ×&Ñ&Ð'YÔ[^Ð_`Ó[aÔbÜÐ8¸¸Ð<Ó=Ð=ûð	>üs‘   ‚J™;I ÁH8ÁI ÁJÁ$I ÂJÂA-I Ã/?H;
Ä.!I ÅIÅI Å-IÅ./I ÆA
I Ç)AI È7JÈ8I È;I ÉI ÉJÉ-J
Ê
JÊJr²   )NN)NNN)NNNN)T)yrh   ri   rj   r�   r   rƒ   rm   r   rl   r*   r   ÚobjectrT  rw   r©   Úclassmethodrv   r+   r§   Ústaticmethodrˆ   r   r£   r,   r6   rÑ   rC   rÛ   r0   rÙ   r   rä   re   rË   rÖ   rÕ   rð   rr   r÷   rõ   r  r|   r  r~   r  r   r'  r:  rY  rß   r4   r^  r]  r   r5   ry   rp  r‚  r”  r8  r9  r¡  rs  rq  ro  r„  r…  rà  rƒ  rr  r  r±  r  r2   rý  rŸ  r.   r?  rD  r\  r1   r/   rG  rH  r@   rI  rA   rJ  r   r   rK  r€  r´  r£  r²  r‰  rŽ  r¢  r   r!   r   r>   r»  rÔ  rØ  rá  rÑ  r   rD   r	  rã  rä  r  rÞ  r  r#  r'  r   r-  r<  Ú__classcell__)r°   s   @rp   r�   r�   Ñ   sÄ  ø… ð 37Ð ¨$¡Ó6ð +/Ø'+Ø27ØIMØ14Ø03Ø14Ø"LñA
à  4™ZðA
ð  ™*ðA
ð %)¨4¡Kð	A
ð
 )¨7°3¸°;Ñ+?Ñ?À$ÑFðA
ð #(¨$¡,ðA
ð "'¨¡ðA
ð #(¨$¡,ðA
ð  õA
ðF ð
¨$Ð/BÑ*Cò 
ó ð
ð ðÐ":¸WÀSÈ&À[Ñ=QÑ"QÐTXÑ"Xð Ð]aÐbeÐgjÐbjÑ]kÐnrÑ]rò ó ðð6¸dÐCSÑ>TÐW[Ñ>[ð Ð`nó ð2 37ñà˜Ñ%ðð Ð'Ñ(¨4Ñ/ðð 
ó	ð4Ø˜mÑ+ðØ<@ðà	Ð Ñ	!óð2 37Ø/3ñ	àÐ)Ñ*ðð Ð'Ñ(¨4Ñ/ðð ˜Ñ%¨Ñ,ð	ð
 
óð,Ð5Eð È$ÐOaÑJbÐeiÑJió ð,5Ð);ð 5Ð@Ró 5ð°$Ð7GÑ2HÈ4Ñ2Oð ÐTXÐYkÑTló ð,J°ó Jð
àÐ'Ñ(¨4Ñ/ð
ð 
&ó
ð2°4Ð8HÑ3Ið ÐX[ð Ð`cÐfjÑ`jó ð ðÐ&6ð ¸3ò ó ðð$à!Ð"2Ñ3ð$ð ð$ð �C‰yð	$ð
 
ˆs�Cˆx‰˜4Ñ	ó$ð6L
à�C‰yðL
ð ,ðL
ð ð	L
ð
 Ð1Ñ2ðL
ð 
(óL
ð\"àð"ð ð"ð ˜S #˜X‘¨Ñ-ð	"ð
 "ð"ð 
ó"ðHàÐ 0Ñ1°DÑ8ðð "&Ð&6Ñ!7ðð ˜S™	 DÑ(ð	ð
 
ÐÑ	óò2$,ðX #Ø%)Ø#'ñCð ðCð ð	Cð
 ðCð �t‘ðCð ˜d‘{ðCð ˜D‘jóCðP 37Ø15Ø$(Ø9=ñ
àÐ)Ñ*ð
ð Ð'Ñ(¨4Ñ/ð
ð ×'Ñ'¨$Ñ.ð	
ð
 ˜T‘kð
ð 0°$Ñ6ð
ð 
"ó
ðD 37Ø15Ø$(Ø9=ñeàÐ)Ñ*ðeð Ð'Ñ(¨4Ñ/ðeð ×'Ñ'¨$Ñ.ð	eð
 ˜T‘kðeð 0°$Ñ6ðeð 
"óeðNHàÐ,Ñ-ðHð # 3¨ 8Ñ,ðHð #ð	Hð
 ðHð �t‘ðHð ˜T‘kðHð (ðHð ðHð ðHð !%Ð%:Ñ ;ðHð 
Ð(¨#Ð-Ñ	.óHðT0dàÐ,Ñ-ð0dð # 3¨ 8Ñ,ð0dð #ð	0dð
 ð0dð �t‘ð0dð ˜T‘kð0dð (ð0dð ð0dð !%Ð%:Ñ ;ð0dð 
"ó0dðd[LàÐ,Ñ-ð[Lð # 3¨ 8Ñ,ð[Lð #ð	[Lð
 ð[Lð �t‘ð[Lð ˜T‘kð[Lð (ð[Lð ð[Lð !%Ð%:Ñ ;ð[Lð 
"ó[Lðz'
àŸ™ð'
ð ð'
ð ˜T‘kð	'
ð
 (ð'
ð ð'
ð ˜t™ð'
ð !)Ð)>Ñ ?ð'
ð 
ó'
ðR 
à1ð 
ð ˜T‘kð 
ð (ð	 
ð
 ð 
ð ˜t™ð 
ð 
ó 
ðD$
àð$
ð ˜T‘kð$
ð (ð	$
ð
 ð$
ð ˜t™ð$
ð !)Ð)>Ñ ?ð$
ð 
ó$
ðL ð°HÐ=OÑ4Pð ÐUYò ó ðð ð.
ØÐ,Ñ-ð.
àð.
ð 
ˆuÐ'¨Ð,Ñ-¨sÐ2Ñ	3ò.
ó ð.
ð` ð2JØÐ,Ñ-ð2Jà	ˆuÐ'¨Ð,Ñ-¨uÐ5GÈÐ5LÑ/MÐMÑ	NÐQUÑ	Uò2Jó ð2Jðh ð!X¨cð !X°cò !Xó ð!XðF ð^¨&ð ^°Tò ^ó ð^ð2 ðJØÐ 9Ñ:ðJà	!òJó ðJðX ð
ØÐ 9Ñ:ð
à	ò
ó ð
ð ð
 HÐ-BÑ$Cð 
ÐH]ò 
ó ð
ð ðxØÐ 9Ñ:ðxà	ˆuÐ.°Ð3Ñ4°cÐ9Ñ	:òxó ðxð4 ð8*ØÐ-¨sÐ2Ñ3ð8*à	ˆuÐ+¨SÐ0Ñ1°4Ð7Ñ	8ò8*ó ð8*ð@ '+ñLà.ðLð ˜T‘kðLð (ð	Lð
 ðLð  $ðLð 
�‰óLð` ð
ØÐ3Ñ4ð
Ø=AÀ#¹Yð
à	Ð"Ñ	#ò
ó ð
ð* 37Ø15ñ	%
àÐ)Ñ*ð%
ð Ð'Ñ(¨4Ñ/ð%
ð ×'Ñ'¨$Ñ.ð	%
ð
 
Ð"Ñ	#ó%
ðT 37Ø15Ø$(Ø9=ñh*àÐ)Ñ*ðh*ð Ð'Ñ(¨4Ñ/ðh*ð ×'Ñ'¨$Ñ.ð	h*ð
 ˜T‘kðh*ð 0°$Ñ6ðh*ð 
"óh*ðT0Ø6¸Ñ=ð0à	Ð$Ñ	%ó0ðd ð
Ø0ð
à	ˆc�3ˆh‰ò
ó ð
ð ðG°$ð G¸?ò Gó ðGð ðØÐ/Ñ0ðà	òó ðð UYñ
ØÐ5Ñ6ð
ØFJÈTÁkð
à	Ð0Ñ	0ó
ð0JÀó JðB-¸u¿~¹~ð -ÐRaó -ð2&ÀÇÁð &ÐSXÐY\Ð^aÐYaÑSbó &ð4Ø0ðØCFÈÁ:ðà	óð>Ð:Rð ÐW[Ð\_ÑW`ó ð4AÐ5Mð AÐRVÐW[ÑR\ó AðH OSñ#=Ø0ð#=Ø@DÀtÁð#=à	Ð0Ñ	0ó#=ðJKÐBZð KÐ_có KðZAà)ðAð ðAð ð	Að
 $ðAð 
�S‰˜4Ñ	 $Ñ	&óAðFCàðCð *ðCð $ó	CðJGjàðGjð *óGjðXàÐ'Ñ(ðð %=ðð 
ÐÑ	ó	ðBKà)ðKð ðKð ð	Kð
 
Ð+¨TÐ1Ñ	2óKðZ"ÐNfð "ÐkoÐpsÑktó "ð.( ØÐ-Ñ.ð( Ø>BÀ3¹ið( à	ÐÑ	ó( ðT*Ø  ™Ið*Ø59¸#±Yð*ØORð*à	ˆt�C‰y˜#ˆ~Ñ	ó*ð>fà #Ñ%ðfð %=ðfð 
ó	fð6]¸×9NÑ9Nð ]Ð^bÐcfÑ^gð ]Ðlpó ]ðB ð Yò ó ðð$
Ð<Tð 
ÐY]ó 
ð3à�C‰yð3ð ,ð3ð ð	3ð
 
Ð-Ñ	.ó3ðt 6:ñJ>à+ðJ>ð ðJ>ð Ð1Ñ2ð	J>ð
 Ð1Ñ2ðJ>ð 
%÷J>ro   r�   )…ÚosÚsysÚpathÚinsertÚabspathr•  r`  rL  Úreró  Úcollections.abcr   r   r   r   r   Ú	itertoolsr   r	   Útypingr
   r   r   r   r   r   r   r   r8  Úfastapir   Úpydanticr   r   rß   Úlitellm._loggingr   Úlitellm.cachingr   Úlitellm.constantsr   Úlitellm.exceptionsr   r  r   Ú'litellm.litellm_core_utils.core_helpersr   Ú7litellm.litellm_core_utils.llm_cost_calc.guardrail_costr   Ú9litellm.llms.anthropic.chat.guardrail_translation.handlerr   Ú1litellm.llms.base_llm.guardrail_translation.utilsr   Ú!litellm.llms.bedrock.base_aws_llmr   Ú&litellm.llms.custom_httpx.http_handlerr   r    Úlitellm.proxy._typesr!   Ú'litellm.proxy.common_request_processingr"   Ú(litellm.proxy.common_utils.sse_keepaliver#   Ú&litellm.proxy.guardrails.anthropic_sser$   r%   r&   r'   r(   Úlitellm.secret_managers.mainr)   rÜ  r*   r+   Úlitellm.types.llms.openair,   r-   ÚAlitellm.types.proxy.guardrails.guardrail_hooks.bedrock_guardrailsr.   r/   r0   r1   r2   r3   r4   r5   r6   r7   rò  r8   rO  r9   r5  r;   Ú*litellm.litellm_core_utils.litellm_loggingr<   r/  r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rH   rm   Ú	frozensetrK   rL   rN   rP   ÚcompilerQ   rR   rT   rX   r]   r`   rˆ   rl   rc   re   rr   ry   r~   rŠ   rv   r�   r�   rn   ro   rp   ú<module>r`     s  ðô 
Û 
à ‡�‡���2—7‘7—?‘? 7Ó+Ô ,Û Û Û Û 	Û 
Û ß =Ñ =ß 'ß )ß [× [Ó [ã Ý !ß 1ã Ý 1Ý %Ý HÝ 6Ý AÝ VÝ ZÝ ^õõ 9÷õ 0Ý TÝ M÷õ õ 8ß Rß Q÷÷ ÷ õ :áÝ6Ý0åW÷÷ ÷ ð "€�Ó !Ù(1°9¸hÐ2GÓ(HÐ  Ó Hð.Ð # Uó ð 89Ð -¨uÓ 8Ø7:Ð -¨uÓ :Ø'˜RŸZ™Z¨Ó.Ð �UÓ .à/IÐ % uÓ Ið -/Ð " EÓ .Ù$-Ò.gÓ$hÐ ˜EÓ hð,Ð ! 5ó ð +ØñKÐ ˜E $ sÐ,EÐ'EÑ"FÑGó ñ *3°H¸kÐ3JÓ)KÐ  Ó Kô0˜ô 0ô% :ô %ô 
ô ô.
 Zô 
ðE tð E°ó Eð	C°°d±ð 	CÀÀTÁ
ó 	CôQ.>�¨
õ Q.>ro   