Ë
    tPêjª}  ã                   ó¨  — U d dl Z d dlZd dlZd dlZd dlmZ d dlmZ d dlmZm	Z	m
Z
mZ d dlmZ d dlmZ d dlZd dlmZ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mZ d dlmZ d dl m!Z! d dl"m#Z# d dl$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+ dZ,e
e-d<   dZ.e
e-d<   ddgZ/e
e0e1      e-d<   ed   Z2e	ez  e'z  e)z  Z3da4erd dl5m6Z6  G d„ de«      Z7 G d„ de«      Z8y)é    N)ÚAsyncGenerator©Údatetime)ÚTYPE_CHECKINGÚAnyÚFinalÚLiteral)Úurljoin)ÚHTTPException)Ú	DualCacheÚModelResponse)Úverbose_proxy_logger)Ú%LiteLLMResponsesTransformationHandler)ÚCustomGuardrail)ÚMockResponseIterator)Úget_async_httpx_clientÚhttpxSpecialProvider)Ústream_chunk_builder)ÚUserAPIKeyAuth)ÚGuardrailEventHooks)Ú	CallTypesÚCallTypesLiteralÚEmbeddingResponseÚGuardrailStatusÚImageResponseÚModelResponseStreamÚTextCompletionResponseÚuserÚ	USER_ROLEÚ	assistantÚASSISTANT_ROLEÚsensitiveDataÚdataDetectorÚSENSITIVE_DATA_DETECTOR_KEYS)r   r    F)ÚGuardrailConfigModelc                   óH   ‡ — e Zd ZdZdefˆ fd„Zdeeef   dz  defd„Z	ˆ xZ
S )ÚNomaBlockedMessagez5Exception raised when Noma guardrail blocks a messageÚclassification_responsec                 ó.   •— t         ‰| �  dd|dœ¬«       y )Ni�  z!Request blocked by Noma guardrail)ÚerrorÚdetails)Ústatus_codeÚdetail)ÚsuperÚ__init__)Úselfr(   Ú	__class__s     €úw/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/guardrails/guardrail_hooks/noma/noma.pyr/   zNomaBlockedMessage.__init__B   s#   ø€ Ü‰ÑØà<Ø2ñð 	õ 	
ó    Ú
result_objNÚreturnc                 óN   — |rt        |t        «      sy|j                  d«      du S ©a   
        Check if a result object has a "result" field that is True.

        Args:
            result_obj: A dictionary that may contain a "result" field

        Returns:
            True if the "result" field exists and is True, False otherwise
        FÚresultT©Ú
isinstanceÚdictÚget©r0   r4   s     r2   Ú_is_result_truez"NomaBlockedMessage._is_result_trueK   ó'   € ñ ¤¨J¼Ô!=Øà�~‰~˜hÓ'¨4Ð/Ð/r3   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r;   r/   Ústrr   Úboolr>   Ú__classcell__©r1   s   @r2   r'   r'   ?   s2   ø„ Ù?ð
°õ 
ð0¨$¨s°C¨x©.¸4Ñ*?ð 0ÀD÷ 0r3   r'   c                   ó  ‡ — e Zd ZdZdZdZedee   fd„«       Z		 	 	 	 	 	 d7de
dz  de
dz  d	e
dz  d
edz  dedz  dedz  fˆ fd„Z	 	 d8d„Z	 d9dedededz  de
dz  fd„Z	 d9dededededz  de
dz  f
d„Zdedefd„Zdedefd„Zdedede
dz  fd„Zdededefd„Zdee
ef   dz  defd„Zdede
fd„Zdede
fd „Zdededdfd!„Zdedededdfd"„Zd#ed$e
deddfd%„Zd&ed'e d(ed)e!de"e
z  ez  dz  f
d*„Z#d(ed&ed)e!de"e
z  ez  dz  fd+„Z$d(ed&edefd,„Z%	 d9dedededz  de"e
z  ez  dz  fd-„Z&	 d9dededededz  def
d.„Z'd/ed0e
dz  deded1edefd2„Z(d#ed$e
deddfd3„Z)e*de+d4   dz  fd5„«       Z,d&ededede-e.df   fd6„Z/ˆ xZ0S ):ÚNomaGuardrailz»
    Noma Security Guardrail for LiteLLM

    This guardrail integrates with Noma Security's AI-DR API to provide
    content moderation and safety checks for LLM inputs and outputs.
    úhttps://api.noma.security/z/ai-dr/v2/prompt/scanr5   c                 ó~   — t         j                  t         j                  t         j                  t         j                  gS ©N)r   Úpre_callÚduring_callÚ	post_callÚpre_mcp_call)Úclss    r2   Úget_supported_event_hooksz'NomaGuardrail.get_supported_event_hooksf   s2   € ô  ×(Ñ(Ü×+Ñ+Ü×)Ñ)Ü×,Ñ,ð	
ð 	
r3   NÚapi_keyÚapi_baseÚapplication_idÚmonitor_modeÚblock_failuresÚanonymize_inputc                 ó¶  •— t         st        j                  dt        d¬«       da t	        t
        j                  ¬«      | _        t        «       | _	        |xs t        j                  j                  d«      | _        |xs. t        j                  j                  dt        j                  «      | _        |xs t        j                  j                  d«      | _        d	| _        |€7t        j                  j                  d
d«      j'                  «       dk(  | _        n|| _        |€7t        j                  j                  dd«      j'                  «       dk(  | _        n|| _        |€7t        j                  j                  dd«      j'                  «       dk(  | _        n|| _        |j/                  dt1        | j3                  «       «      «       t5        ‰| �l  di |¤Ž y )Nz�Guardrail provider 'noma' is deprecated. Please migrate to 'noma_v2'. The legacy 'noma' API will no longer be supported after March 31, 2026.é   )Ú
stacklevelT)Úllm_providerÚNOMA_API_KEYÚNOMA_API_BASEÚNOMA_APPLICATION_IDÚlitellmÚNOMA_MONITOR_MODEÚfalseÚtrueÚNOMA_BLOCK_FAILURESÚNOMA_ANONYMIZE_INPUTÚsupported_event_hooks© )Ú_LEGACY_NOMA_DEPRECATION_WARNEDÚwarningsÚwarnÚDeprecationWarningr   r   ÚGuardrailCallbackÚasync_handlerr   Ú_responses_transform_handlerÚosÚenvironr<   rS   rI   Ú_DEFAULT_API_BASErT   rU   Údefault_application_idÚlowerrV   rW   rX   Ú
setdefaultÚlistrR   r.   r/   )	r0   rS   rT   rU   rV   rW   rX   Úkwargsr1   s	           €r2   r/   zNomaGuardrail.__init__o   st  ø€ õ /Ü�M‰MðZô #Øõð /3Ð+ä3ÔAU×AgÑAgÔhˆÔÜ,QÓ,SˆÔ)ØÒ@¤"§*¡*§.¡.°Ó"@ˆŒØ Òd¤B§J¡J§N¡N°?ÄM×DcÑDcÓ$dˆŒØ,ÒU´·
±
·±Ð?TÓ0UˆÔØ&/ˆÔ#àÐÜ "§
¡
§¡Ð/BÀGÓ L× RÑ RÓ TÐX^Ñ ^ˆDÕà ,ˆDÔàÐ!Ü"$§*¡*§.¡.Ð1FÈÓ"O×"UÑ"UÓ"WÐ[aÑ"aˆDÕà"0ˆDÔàÐ"Ü#%§:¡:§>¡>Ð2HÈ'Ó#R×#XÑ#XÓ#ZÐ^dÑ#dˆDÕ à#2ˆDÔ à×ÑÐ1´4¸×8VÑ8VÓ8XÓ3YÔZÜ‰ÑÑ"˜6Ó"r3   c                 óˆ   — 	 t        j                  |«       y# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w)zJCreate a background task for Noma API calls without blocking the main flowz)Failed to create background Noma task: %sN)ÚasyncioÚcreate_taskÚ	Exceptionr   r*   )r0   ÚcoroÚes      r2   Ú_create_background_noma_checkz+NomaGuardrail._create_background_noma_check�   s=   € ð
	WÜ×Ñ Õ%øÜò 	WÜ ×&Ñ&Ð'RÐTU×VÑVûð	Wús   ‚ ˜	A¡<¼AÚrequest_dataÚ	user_authÚ
event_typec           
   ƒ   ó  K  — t        j                  «       }| j                  |«      }|j                  d«      xs g }|sy| j                  j                  |«      \  }}|rddd|dœgdœ}	|j                  d|	«       |syd	|i}
| j                  |
d|||¬
«      ƒ d{  –—† }t        j                  «       }||z
  j                  «       }| j                  |«      }| j                  d||||j                  «       |j                  «       ||¬«       | j                  rG| j                  t        t        j                   |«      |«      ƒ d{  –—†  t        j                   |«      S | j#                  |t        «      rB| j%                  |t        «      }|r*| j'                  ||«       t)        j*                  d|«       |S | j-                  t        t        j                   |«      |«      ƒ d{  –—†  t        j                   |«      S 7 �Œd7 Œ»7 Œ­w)z/Shared logic for processing user message checksÚmessagesNÚmessageÚsystemÚ
input_text©ÚtypeÚtext©r‡   ÚroleÚcontentr   Úinput©ÚpayloadÚllm_request_idr~   r   Ú
extra_dataÚnoma©Úguardrail_providerÚguardrail_json_responser~   Úguardrail_statusÚ
start_timeÚend_timeÚdurationr€   z*Noma guardrail anonymized user message: %s)r   ÚnowÚ)get_guardrail_dynamic_request_body_paramsr<   rn   Ú1convert_chat_completion_messages_to_responses_apiÚinsertÚ_call_noma_apiÚtotal_secondsÚ_determine_guardrail_statusÚ:add_standard_logging_guardrail_information_to_request_dataÚ	timestamprV   Ú_handle_verdict_backgroundr   ÚjsonÚdumpsÚ_should_anonymizeÚ_extract_anonymized_contentÚ_replace_user_message_contentr   ÚdebugÚ_check_verdict)r0   r~   r   r€   r–   r�   r‚   Úinput_itemsÚinstructionsÚsystem_messagerŽ   Úresponse_jsonr—   r˜   r•   Úanonymized_contents                   r2   Ú_process_user_message_checkz)NomaGuardrail._process_user_message_check§   s  è ø€ ô %ŸL™L›Nˆ
Ø ×JÑJÈ<ÓXˆ
à&×*Ñ*¨:Ó6Ò<¸"ˆÙØà$(×$EÑ$E×$wÑ$wØó%
Ñ!ˆ�\ñ à!Ø à)°<Ñ@ðñ%ˆNð ×Ñ˜q .Ô1áØà! ;Ð/ˆØ%)×%8Ñ%8ØØØ%ØØ!ð &9ó &
÷  
ˆô #Ÿ,™,›.ˆØ# jÑ0×?Ñ?ÓAˆð #'×"BÑ"BÀ=Ó"QÐð 	×GÑGØ%Ø$1Ø%Ø-Ø!×+Ñ+Ó-Ø×'Ñ'Ó)ØØ!ð 	Hô 		
ð ×ÒØ×1Ñ1´)¼T¿Z¹ZÈÓ=TÐVcÓd×dÐdÜ—:‘:˜kÓ*Ð*ð ×!Ñ! -´Ô;Ø(,×(HÑ(HÈÔXaÓ(bÐÙ!à×2Ñ2°<ÐASÔTÜ$×*Ñ*Ð+WÐYkÔlØ)Ð)à×!Ñ!¤)¬T¯Z©Z¸Ó-DÀmÓT×TÐTÜ�z‰z˜+Ó&Ð&ðQ 
ùð6 eøð 	Uús8   ‚BHÂH ÂB*HÅHÅBHÇ&HÇ'HÈHÈHÚresponsec           
   ƒ   ó,  K  — t        j                  «       }| j                  |«      }t        |t        j
                  «      syd}|j                  D ]K  }t        |t        j                  «      sŒ|j                  j                  sŒ5|j                  j                  } n |rt        |t        «      sydddd|dœgdœgi}	| j                  |	|j                  |||¬«      ƒ d{  –—† }
t        j                  «       }||z
  j                  «       }| j                  |
«      }| j                  d	|
|||j!                  «       |j!                  «       ||¬
«       | j"                  r4| j%                  t&        t)        j*                  |«      |
«      ƒ d{  –—†  |S | j-                  |
t&        «      rB| j/                  |
t&        «      }|r*| j1                  ||«       t3        j4                  d|«       |S | j7                  t&        ||
«      ƒ d{  –—†  |S 7 �Œ+7 Œ‚7 Œ­w)z/Shared logic for processing LLM response checksNrŒ   rƒ   r    r…   r†   r‰   r�   r‘   r’   z*Noma guardrail anonymized LLM response: %s)r   r™   rš   r:   r`   r   ÚchoicesÚChoicesrƒ   r‹   rD   r�   Úidrž   rŸ   r    r¡   rV   r¢   r!   r£   r¤   r¥   r¦   Ú_replace_llm_response_contentr   r¨   r©   )r0   r~   r°   r   r€   r–   r�   r‹   ÚchoicerŽ   r­   r—   r˜   r•   r®   s                  r2   Ú_process_llm_response_checkz)NomaGuardrail._process_llm_response_checkñ   s  è ø€ ô %ŸL™L›Nˆ
Ø ×JÑJÈ<ÓXˆ
ä˜(¤G×$9Ñ$9Ô:ØàˆØ×&Ñ&ò 	ˆFÜ˜&¤'§/¡/Õ2°v·~±~×7MÓ7MØ Ÿ.™.×0Ñ0�Ùð	ñ
 œj¨´#Ô6Øð à%Ø'Ø)5¸wÑ GÐHñðð
ˆð &*×%8Ñ%8ØØ#Ÿ;™;Ø%ØØ!ð &9ó &
÷  
ˆô #Ÿ,™,›.ˆØ# jÑ0×?Ñ?ÓAˆð #'×"BÑ"BÀ=Ó"QÐð 	×GÑGØ%Ø$1Ø%Ø-Ø!×+Ñ+Ó-Ø×'Ñ'Ó)ØØ!ð 	Hô 		
ð ×ÒØ×1Ñ1´.Ä$Ç*Á*ÈWÓBUÐWdÓe×eÐeØˆNð ×!Ñ! -´Ô@Ø(,×(HÑ(HÈÔXfÓ(gÐÙ!à×2Ñ2°8Ð=OÔPÜ$×*Ñ*Ð+WÐYkÔlØ)Ð)à×!Ñ!¤.°'¸=ÓI×IÐIØˆðQ 
ùð6 føð 	JúsE   ‚A,HÁ/HÂAHÃ"HÃ#B*HÆHÆA8HÈHÈHÈHÈHr­   c                 ó¸   — 	 t        |t        «      sy|j                  dd«      }|du ry|du ryy# t        $ r }t	        j
                  d|«       Y d}~yd}~ww xY w)	ax  
        Determine the guardrail status based on NOMA API response.

        Args:
            response_json: Response from NOMA API

        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
        Úguardrail_failed_to_respondÚaggregatedScanResultFÚsuccessTÚguardrail_intervenedz+Error determining NOMA guardrail status: %sN)r:   r;   r<   rz   r   r*   )r0   r­   Úaggregated_scan_resultr|   s       r2   rŸ   z)NomaGuardrail._determine_guardrail_status=  so   € ð	1ä˜m¬TÔ2Ø4ð -:×,=Ñ,=Ð>TÐV[Ó,\Ð"ð &¨Ñ.Ø ð &¨Ñ-Ø-ð 1øäò 	1Ü ×&Ñ&Ð'TÐVWÔXÜ0ûð	1ús   ‚0 “0 ª0 °	A¹AÁAÚclassification_objc                 ó   — |syg }d}|j                  «       D ]Ó  \  }}|t        v r=t        |t        «      r-|j                  «       D ]  \  }}| j	                  |«      sŒd}Œ ŒKt        |t        «      r(d|v r$| j	                  |«      sŒq|j                  |«       Œƒt        |t        «      sŒ”|j                  «       D ]-  \  }}	| j	                  |	«      sŒ|j                  |› d|› �«       Œ/ ŒÕ |xr t        |«      dk(  S )aC  
        Check if only sensitive data detectors (PII, PCI, secrets) have result=true in the classification.

        Args:
            classification_obj: The prompt or response classification object from Noma API

        Returns:
            True if only sensitiveData detectors have result=true, False otherwise
        FTr8   ú.r   )Úitemsr$   r:   r;   r>   ÚappendÚlen)
r0   r¾   Úfailed_detectorsÚsensitive_data_detectedÚkeyÚvalueÚ	data_typeÚdata_resultÚ
nested_keyÚnested_values
             r2   Ú"_should_only_sensitive_data_failedz0NomaGuardrail._should_only_sensitive_data_faileda  s
  € ñ "Øð #%ÐØ"'Ðà,×2Ñ2Ó4ò 	G‰JˆC�ØÔ2Ñ2´zÀ%ÌÔ7Nà.3¯k©k«mò 7Ñ*�I˜{Ø×+Ñ+¨KÕ8Ø26Ñ/ñ7ô
 ˜E¤4Ô(¨X¸Ñ->à×'Ñ'¨Õ.Ø$×+Ñ+¨CÕ0ä˜E¤4Õ(à05·±³ò GÑ,�J Ø×+Ñ+¨LÕ9Ø(×/Ñ/°3°%°q¸¸Ð0EÕFñGð	Gð( 'ÒE¬3Ð/?Ó+@ÀAÑ+EÐEr3   Úmessage_typec                 óÌ   — |j                  dg «      }|sy|D ]J  }|j                  d«      |k(  sŒ|j                  di «      j                  di «      j                  dd«      c S  y)aD  
        Extract anonymized content from Noma API response.

        Args:
            response_json: The full response from Noma API
            message_type: Either 'user' or 'assistant' to determine which content to extract

        Returns:
            The anonymized content string if available, None otherwise
        Ú
scanResultNrŠ   ÚresultsÚanonymizedContentÚ
anonymizedÚ )r<   )r0   r­   rÍ   Úscan_resultÚresult_items        r2   r¦   z)NomaGuardrail._extract_anonymized_contentˆ  ss   € ð +×.Ñ.¨|¸RÓ@ˆÙØð 'ò 	iˆKØ�‰˜vÓ&¨,Ó6Ø"—‘ y°"Ó5×9Ñ9Ð:MÈrÓR×VÑVÐWcÐegÓhÒhð	ið r3   c                 óD  — | j                   s| j                  sy|j                  dd«      }|sy|j                  dg «      }|syt        |t        «      rt        |«      dk(  ry|D ]9  }|j                  d«      |k(  sŒ| j                  |j                  di «      «      c S  y)aˆ  
        Determine if content should be anonymized based on Noma API response.

        Logic:
        - If aggregatedScanResult=False: Content is safe, anonymize if anonymized version exists
        - If aggregatedScanResult=True: Check if only sensitiveData detectors have result=True
          - If yes: Anonymize
          - If no: Block (other violations detected)

        Args:
            response_json: The full response from Noma API
            message_type: Either 'user' or 'assistant' to determine which classification to check

        Returns:
            True if content should be anonymized, False if it should be blocked
        Frº   TrÏ   r   rŠ   rÐ   )rV   rX   r<   r:   ru   rÃ   rÌ   )r0   r­   rÍ   r½   rÔ   rÕ   s         r2   r¥   zNomaGuardrail._should_anonymizeŸ  s®   € ð$ ×Ò D×$8Ò$8Øð )6×(9Ñ(9Ð:PÐRWÓ(XÐñ &Øð +×.Ñ.¨|¸RÓ@ˆÙØä˜+¤tÔ,´°KÓ0@ÀAÒ0EØà&ò 	_ˆKØ�‰˜vÓ&¨,Ó6Ø×>Ñ>¸{¿¹ÈyÐZ\Ó?]Ó^Ò^ð	_ð r3   r4   c                 óN   — |rt        |t        «      sy|j                  d«      du S r7   r9   r=   s     r2   r>   zNomaGuardrail._is_result_trueÉ  r?   r3   r®   c                 ó´   — |j                  dg «      }|syt        t        |«      dz
  dd«      D ]'  }||   j                  d«      t        k(  sŒ|||   d<    y y)zå
        Replace the user message content in request data with anonymized version.

        Args:
            request_data: The original request data
            anonymized_content: The anonymized content to replace with
        r‚   Né   éÿÿÿÿrŠ   r‹   )r<   ÚrangerÃ   r   )r0   r~   r®   r‚   Úis        r2   r§   z+NomaGuardrail._replace_user_message_contentØ  se   € ð '×*Ñ*¨:°rÓ:ˆÙØô ”s˜8“} qÑ(¨"¨bÓ1ò 	ˆAØ˜‰{�‰˜vÓ&¬)Ó3Ø);�˜‘˜IÑ&Ùñ	r3   c                 óâ   — t        |t        j                  «      sy|j                  D ]E  }t        |t        j                  «      sŒ|j
                  j                  sŒ5||j
                  _        ŒG y)zÑ
        Replace the LLM response content with anonymized version.

        Args:
            response: The original LLM response
            anonymized_content: The anonymized content to replace with
        N)r:   r`   r   r²   r³   rƒ   r‹   )r0   r°   r®   r¶   s       r2   rµ   z+NomaGuardrail._replace_llm_response_contentê  sT   € ô ˜(¤G×$9Ñ$9Ô:Øð ×&Ñ&ò 	<ˆFÜ˜&¤'§/¡/Õ2°v·~±~×7MÓ7MØ);�—‘Õ&ñ	<r3   c              ƒ   óž   K  — 	 | j                  ||«      ƒ d{  –—†  y7 Œ# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w­w)z@Check user message in background for monitor mode - non-blockingNz-Noma background user message check failed: %s)r¯   rz   r   r*   )r0   r~   r   r|   s       r2   Ú_check_user_message_backgroundz,NomaGuardrail._check_user_message_backgroundú  sH   è ø€ ð	[Ø×2Ñ2°<ÀÓK×KÒKùÜò 	[Ü ×&Ñ&Ð'VÐXY×ZÑZûð	[üs6   ‚A„! ™š! žAŸ! ¡	A
ªAÁ AÁA
Á
Ac              ƒ   ó    K  — 	 | j                  |||«      ƒ d{  –—†  y7 Œ# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w­w)z@Check LLM response in background for monitor mode - non-blockingNz)Noma background response check failed: %s)r·   rz   r   r*   )r0   r~   r°   r   r|   s        r2   Ú_check_llm_response_backgroundz,NomaGuardrail._check_llm_response_background  sJ   è ø€ ð	WØ×2Ñ2°<ÀÈ9ÓU×UÒUùÜò 	WÜ ×&Ñ&Ð'RÐTU×VÑVûð	Wüs6   ‚A„" š ›" ŸA " ¢	A«AÁAÁAÁAr‡   rƒ   c              ƒ   ó  K  — 	 |j                  dd«      }|rd|› d|› �}t        j                  |«       yd|› d|› �}t        j                  |«       y# t        $ r }t        j
                  d|«       Y d}~yd}~ww xY w­w)zžHandle aggregatedScanResult from Noma API in background - logging only, never blocks
        aggregatedScanResult=True means unsafe, False means safe
        rº   FúNoma guardrail blocked ú
 message: úNoma guardrail allowed z+Noma background verdict handling failed: %sN)r<   r   ÚwarningÚinforz   r*   )r0   r‡   rƒ   r­   r½   Úmsgr|   s          r2   r¢   z(NomaGuardrail._handle_verdict_background  sŠ   è ø€ ð	Yà,9×,=Ñ,=Ð>TÐV[Ó,\Ð"á%Ø/°¨v°ZÀ¸yÐI�Ü$×,Ñ,¨SÕ1à/°¨v°ZÀ¸yÐI�Ü$×)Ñ)¨#Õ.øÜò 	YÜ ×&Ñ&Ð'TÐVW×XÑXûð	Yüs8   ‚B „1A µB ¶A ÁB Á	A=ÁA8Á3B Á8A=Á=B Úuser_api_key_dictÚcacheÚdataÚ	call_typec              ƒ   ó<  K  — t        j                  d«       t        j                  }|t        j
                  j                  k(  rt        j                  }| j                  ||¬«      du r|S | j                  r$	 | j                  | j                  ||«      «       |S 	 | j                  ||t        j                  «      ƒ d {  –—† S # t        $ r!}t        j                  d|«       Y d }~|S d }~ww xY w7 Œ1# t        $ r ‚ t        $ r’}ddlm}  |j"                  «       }| j%                  dt'        |«      |d|j)                  «       |j)                  «       d	t        j                  ¬
«       t        j                  d|«       | j*                  r‚ |cY d }~S d }~ww xY w­w)NzRunning Noma pre-call hook©rë   r€   Fz2Failed to start background Noma pre-call check: %sr   r   r‘   r¹   ç        r’   zNoma pre-call hook failed: %s)r   r¨   r   rM   r   Úcall_mcp_toolrÇ   rP   Úshould_run_guardrailrV   r}   rß   rz   r*   Ú_check_user_messager'   r   r™   r    rD   r¡   rW   )	r0   ré   rê   rë   rì   r€   r|   r   r–   s	            r2   Úasync_pre_call_hookz!NomaGuardrail.async_pre_call_hook'  s‚  è ø€ ô 	×"Ñ"Ð#?Ô@ä(×1Ñ1ˆ
Øœ	×/Ñ/×5Ñ5Ò5Ü,×9Ñ9ˆJà×$Ñ$¨$¸:Ð$ÓFÈ%ÑOØˆKð ×ÒðdØ×2Ñ2°4×3VÑ3VÐW[Ð]nÓ3oÔpð ˆKð	Ø×1Ñ1°$Ð8IÔK^×KgÑKgÓh×hÐhøô ò dÜ$×*Ñ*Ð+_Ðab×cÐcØˆKûðdúð
 iùÜ!ò 	àÜò 	å)à , §¡£ˆJØ×KÑKØ#)Ü(+¨A«Ø!Ø!>Ø%×/Ñ/Ó1Ø#×-Ñ-Ó/ØÜ.×7Ñ7ð Lô 	ô !×&Ñ&Ð'FÈÔJà×"Ò"ØØ�Kûð)	üss   ‚A6FÁ9!C ÂFÂ$C5 ÃC3ÃC5 ÃFÃ	C0ÃC+Ã%FÃ+C0Ã0FÃ3C5 Ã5FÄBFÆFÆFÆFÆFc              ƒ   ó  K  — t         j                  }|t        j                  j                  k(  rt         j
                  }| j                  ||¬«      dur|S | j                  r$	 | j                  | j                  ||«      «       |S 	 | j                  ||t         j                  «      ƒ d {  –—† S # t        $ r!}t        j                  d|«       Y d }~|S d }~ww xY w7 Œ1# t        $ r ‚ t        $ r’}ddlm}  |j                   «       }| j#                  dt%        |«      |d|j'                  «       |j'                  «       dt         j                  ¬	«       t        j                  d
|«       | j(                  r‚ |cY d }~S d }~ww xY w­w)Nrî   Tz4Failed to start background Noma moderation check: %sr   r   r‘   r¹   rï   r’   zNoma moderation hook failed: %s)r   rN   r   rð   rÇ   rP   rñ   rV   r}   rß   rz   r   r*   rò   r'   r   r™   r    rD   r¡   rW   )r0   rë   ré   rì   r€   r|   r   r–   s           r2   Úasync_moderation_hookz#NomaGuardrail.async_moderation_hookZ  ss  è ø€ ô +>×*IÑ*Iˆ
Øœ	×/Ñ/×5Ñ5Ò5Ü,×9Ñ9ˆJà×$Ñ$¨$¸:Ð$ÓFÈdÑRØˆKð ×ÒðfØ×2Ñ2°4×3VÑ3VÐW[Ð]nÓ3oÔpð ˆKð	Ø×1Ñ1°$Ð8IÔK^×KjÑKjÓk×kÐkøô ò fÜ$×*Ñ*Ð+aÐcd×eÐeØˆKûðfúð
 lùÜ!ò 	àÜò 	å)à , §¡£ˆJØ×KÑKØ#)Ü(+¨A«Ø!Ø!>Ø%×/Ñ/Ó1Ø#×-Ñ-Ó/ØÜ.×:Ñ:ð Lô 	ô !×&Ñ&Ð'HÈ!ÔLà×"Ò"ØØ�Kûð)	üss   ‚A!FÁ$!B1 ÂFÂ$C  Â,CÂ-C  Â0FÂ1	CÂ:CÃFÃCÃFÃC  Ã FÃ2BE?Å9FÅ:FÅ?FÆFc              ƒ   ó¼  K  — t         j                  }| j                  ||¬«      dur|S | j                  r%	 | j	                  | j                  |||«      «       |S 	 | j                  |||t         j                  «      ƒ d {  –—† S # t        $ r!}t        j                  d|«       Y d }~|S d }~ww xY w7 Œ1# t        $ r ‚ t        $ r’}ddlm}  |j                  «       }| j                  dt        |«      |d|j                  «       |j                  «       dt         j                  ¬	«       t        j                  d
|«       | j                   r‚ |cY d }~S d }~ww xY w­w)Nrî   Tz3Failed to start background Noma post-call check: %sr   r   r‘   r¹   rï   r’   zNoma post-call hook failed: %s)r   rO   rñ   rV   r}   rá   rz   r   r*   Ú_check_llm_responser'   r   r™   r    rD   r¡   rW   )r0   rë   ré   r°   r€   r|   r   r–   s           r2   Úasync_post_call_success_hookz*NomaGuardrail.async_post_call_success_hookŠ  s[  è ø€ ô 2E×1NÑ1Nˆ
Ø×$Ñ$¨$¸:Ð$ÓFÈdÑRØˆOð ×ÒðeØ×2Ñ2Ø×7Ñ7¸¸hÐHYÓZôð
 ˆOð	Ø×1Ñ1°$¸ÐBSÔUh×UrÑUrÓs×sÐsøô ò eÜ$×*Ñ*Ð+`Ðbc×dÐdØˆOûðeúð
 tùÜ!ò 	àÜò 	å)à , §¡£ˆJØ×KÑKØ#)Ü(+¨A«Ø!Ø!>Ø%×/Ñ/Ó1Ø#×-Ñ-Ó/ØÜ.×8Ñ8ð Lô 	ô !×&Ñ&Ð'GÈÔKØ×"Ò"ØØ�Oûð'	üsq   ‚4E·"B ÁEÁ%B5 ÂB3ÂB5 ÂEÂ	B0ÂB+Â%EÂ+B0Â0EÂ3B5 Â5EÃBEÅEÅEÅEÅEc              ƒ   óP   K  — | j                  |||«      ƒ d{  –—† }|s|S |S 7 Œ
­w)z(Check user message for policy violationsN)r¯   )r0   r~   r   r€   Úuser_messages        r2   rò   z!NomaGuardrail._check_user_message¸  s6   è ø€ ð %)×$DÑ$DÀ\ÐS\Ð^hÓ$i×iˆÙØÐàÐð	 jús   ‚&™$š&c              ƒ   óR   K  — | j                  ||||«      ƒ d{  –—† }|s|S |S 7 Œ
­w)z(Check LLM response for policy violationsN)r·   )r0   r~   r°   r   r€   r‹   s         r2   r÷   z!NomaGuardrail._check_llm_responseÅ  s6   è ø€ ð  $×?Ñ?ÀÈhÐXaÐcmÓn×nˆÙØˆOàˆð	 oús   ‚'š%›'rŽ   r�   r�   c              ƒ   óÒ  K  — |j                  d«      }i | j                  rdd| j                  › �ini ¥|rd|ini ¥}t        | j                  xs dt        j
                  «      }| j                  j                  ||i |¥d|j                  d«      xs[ |j                  di «      j                  d	i «      j                  d
«      xs( | j                  xs |j                  xs | j                  |j                  di «      j                  dd «      |j                  r|j                  n|j                  ||dœi¥¬«      ƒ d {  –—† }	|	j                  «        |	j                  «       S 7 Œ$­w)NÚlitellm_call_idÚAuthorizationzBearer zX-Noma-Request-IDrJ   zx-noma-contextrU   ÚmetadataÚheaderszx-noma-application-idÚrequester_ip_address)ÚapplicationIdÚ	ipAddressÚuserIdÚ	sessionIdÚ	requestId)r   r£   )r<   rS   r
   rT   rI   Ú_AIDR_ENDPOINTrm   ÚpostrU   Ú	key_aliasrr   Ú
user_emailÚuser_idÚraise_for_statusr£   )
r0   rŽ   r�   r~   r   r�   Úcall_idr   Úendpointr°   s
             r2   r�   zNomaGuardrail._call_noma_apiÓ  sy  è ø€ ð &×)Ñ)Ð*;Ó<ˆð
Ø>B¿lºl� 7¨4¯<©<¨.Ð!9Ñ:ÐPRð
á18Ð# WÑ-¸bð
ˆô " $§-¡-Ò"OÐ3OÔQ^×QmÑQmÓnˆà $× 2Ñ 2× 7Ñ 7ØØðØðà Ø%/§^¡^Ð4DÓ%Eò &3Ø#×'Ñ'¨
°BÓ7×;Ñ;¸IÀrÓJ×NÑNÐOfÓgò&3à×*Ñ*ò&3ð !×*Ñ*ò&3ð ×2Ñ2Ø!-×!1Ñ!1°*¸bÓ!A×!EÑ!EÐF\Ð^bÓ!cØ7@×7KÒ7K˜y×3Ò3ÐQZ×QbÑQbØ!(Ø!/ñ
#ñð !8ó !
÷ 
ˆð$ 	×!Ñ!Ô#à�}‰}‹Ðð)
ús   ‚D>E'Å E%Å%E'c              ƒ   ój  K  — |j                  dd«      }|r\d|› d|› �}| j                  rt        j                  |«       yt        j                  |«       |j                  di «      }t        |«      ‚d|› d|› �}| j                  rt        j                  |«       yt        j                  |«       y­w)zµ
        Check the aggregatedScanResult from the Noma API and raise an exception if needed.
        aggregatedScanResult=True means unsafe (block), False means safe (allow)
        rº   Frã   rä   rÏ   rå   N)r<   rV   r   ræ   r¨   r'   rç   )r0   r‡   rƒ   r­   r½   rè   Úoriginal_responses          r2   r©   zNomaGuardrail._check_verdictø  s­   è ø€ ð )6×(9Ñ(9Ð:PÐRWÓ(XÐá!Ø+¨D¨6°¸G¸9ÐEˆCà× Ò Ü$×,Ñ,¨SÕ1ä$×*Ñ*¨3Ô/Ø+8×+<Ñ+<¸\È2Ó+NÐ!ä(Ð):Ó;Ð;à+¨D¨6°¸G¸9ÐEˆCØ× Ò Ü$×)Ñ)¨#Õ.ä$×*Ñ*¨3Õ/ùs   ‚B1B3r%   c                  ó   — ddl m}  | S )Nr   ©ÚNomaGuardrailConfigModel)Ú3litellm.types.proxy.guardrails.guardrail_hooks.nomar  r  s    r2   Úget_config_modelzNomaGuardrail.get_config_model  s   € õ	
ð (Ð'r3   c                óÜ  K  — g }|2 3 d{  –—† }|j                  |«       Œ7 Œ6 |syt        |¬«      }t        |t        «      r›	 | j	                  |||t
        j                  «      ƒ d{  –—†7  }nN# t        $ r ‚ t        $ r9}| j                  r‚ t        j                  d|«       |D ]  }|­–— Œ	 Y d}~yd}~ww xY wt        |¬«      }	|	2 3 d{  –—†7  }|­–— Œ6 y|D ]  }|­–— Œ	 y­w)z6Process streaming response chunks with Noma guardrail.N)Úchunksz(Noma streaming post-call hook failed: %s)Úmodel_response)rÂ   r   r:   r   r÷   r   rO   r'   rz   rW   r   r*   r   )
r0   ré   r°   r~   Ú
all_chunksÚchunkÚassembled_model_responseÚprocessed_responser|   Úmock_responses
             r2   Ú'async_post_call_streaming_iterator_hookz5NomaGuardrail.async_post_call_streaming_iterator_hook  s  è ø€ ð 8:ˆ
Ø#÷ 	%ð 	%�%Ø×Ñ˜eÕ$ð	%ø˜8ñ ØäYmØôZ
Ð ô Ð.´Ô>ðØ26×2JÑ2JØ Ø,Ø%Ü'×1Ñ1ó	3÷ -ð -Ñ"øô &ò ØÜò Ø×&Ò&ØÜ$×*Ñ*Ð+UÐWXÔYØ'ò  �EØ”Kð äûðúô $8ÐGYÔ#ZˆMØ,÷ ñ �eØ”ð  -ààò 	ˆEØŒKñ	ùsm   ‚C,‡$‹"Œ$�C,¢$¤ C,Á%A1 Á*A-Á+A1 Á0C,Á1B<Â/B7Â2C,Â7B<Â<C,ÃCÃCÃCÃC,)NNNNNN)r5   NrL   )1r@   rA   rB   rC   rq   r  Úclassmethodru   r   rR   rD   rE   r/   r}   r;   r   r¯   ÚLLMResponser·   r   rŸ   rÌ   ÚMessageRoler¦   r¥   r   r>   r§   rµ   rß   rá   r¢   r   r   rz   ró   rõ   rø   rò   r÷   r�   r©   Ústaticmethodr‡   r  r   r   r  rF   rG   s   @r2   rI   rI   [   s\  ø„ ñð 5ÐØ,€Nàð
¨$Ð/BÑ*Cò 
ó ð
ð #Ø#Ø%)Ø$(Ø&*Ø'+ñ,#à�t‘ð,#ð ˜‘*ð,#ð ˜d™
ð	,#ð
 ˜T‘kð,#ð ˜t™ð,#ð  ™õ,#ð\Wð 
óWð 26ñ	H'àðH'ð "ðH'ð (¨$Ñ.ð	H'ð
 
ˆt‰óH'ð^ 26ñJàðJð ðJð "ð	Jð
 (¨$Ñ.ðJð 
ˆt‰óJðX"1¸ð "1À/ó "1ðH%FÀTð %FÈdó %FðN¸ð È[ð Ð]`ÐcgÑ]gó ð.(¨tð (À;ð (ÐSWó (ðT0¨$¨s°C¨x©.¸4Ñ*?ð 0ÀDó 0ð¸$ð ÐTWó ð$<°kð <ÐWZó <ð 	[àð	[ð "ð	[ð 
ó		[ð
Wàð
Wð ð
Wð "ð	
Wð
 
ó
WðYàðYð ðYð ð	Yð
 
óYð,1à)ð1ð ð1ð ð	1ð
 $ð1ð 
�S‰˜4Ñ	 $Ñ	&ó1ðf.àð.ð *ð.ð $ð	.ð
 
�S‰˜4Ñ	 $Ñ	&ó.ð`,àð,ð *ð,ð ó	,ðd 26ñ	àðð "ðð (¨$Ñ.ð	ð
 
�S‰˜4Ñ	 $Ñ	&óð$ 26ñàðð ðð "ð	ð
 (¨$Ñ.ðð 
óð#àð#ð ˜d™
ð#ð ð	#ð
 "ð#ð ð#ð 
ó#ðJ0àð0ð ð0ð ð	0ð
 
ó0ð< ð(˜dÐ#9Ñ:¸TÑAò (ó ð(ð+à)ð+ð ð+ð ð	+ð
 
Ð+¨TÐ1Ñ	2÷+r3   rI   )9rx   r£   ro   ri   Úcollections.abcr   r   Útypingr   r   r   r	   Úurllib.parser
   Úfastapir   r`   r   r   Úlitellm._loggingr   ÚIlitellm.completion_extras.litellm_responses_transformation.transformationr   Ú%litellm.integrations.custom_guardrailr   Ú)litellm.llms.base_llm.base_model_iteratorr   Ú&litellm.llms.custom_httpx.http_handlerr   r   Úlitellm.mainr   Úlitellm.proxy._typesr   Úlitellm.types.guardrailsr   Úlitellm.types.utilsr   r   r   r   r   r   r   r   Ú__annotations__r!   r$   ru   rD   r!  r   rh   Ú3litellm.types.proxy.guardrails.guardrail_hooks.baser%   r'   rI   rg   r3   r2   ú<module>r2     sØ   ðô Û Û 	Û Ý *Ý ÷ó õ !å !ã ß ,Ý 1õõ BÝ J÷õ .Ý /Ý 8÷÷ ñ ð €	ˆ5Ó Ø#€�Ó #Ø2AÀ>Ð1RÐ ˜e D¨¡IÑ.Ó Rð Ð)Ñ*€Ø�MÑ!Ð$5Ñ5¸ÑE€Ø"'Ð áÝXô0˜ô 0ô8n�Oõ nr3   