
    h:                     j   d dl Z d dlmZmZmZ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 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 erd dlmZ  G d de      Z  G d de      Z! G d d      Z" G d d      Z# G d d      Z$ G d d      Z%dee!   fdZ&dee!   fdZ' G d de      Z(y)    N)TYPE_CHECKINGAnyOptionalProtocolType)HTTPException)verbose_proxy_logger)	DualCache)CustomGuardraillog_guardrail_information)get_async_httpx_clienthttpxSpecialProvider)UserAPIKeyAuth)*add_guardrail_to_applied_guardrails_header)GuardrailEventHooks)LLMResponseTypesModelResponseTextCompletionResponse)GuardrailConfigModelc                       e Zd ZdZy)PangeaGuardrailMissingSecretsz,Custom exception for missing Pangea secrets.N)__name__
__module____qualname____doc__     r/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.pyr   r      s    6r   r   c                   4    e Zd Zdee   fdZdee   defdZy)_Transformerreturnc                      y Nr   selfs    r   get_messagesz_Transformer.get_messages#       r   prompt_messagesc                      y r#   r   r%   r(   s     r   update_original_bodyz!_Transformer.update_original_body&   r'   r   N)r   r   r   listdictr&   r   r+   r   r   r   r    r    "   s)    d4j DJ 3 r   r    c                   :    e Zd Zd Zdee   fdZdee   defdZy)_TextCompletionRequestc                     || _         y r#   bodyr%   r2   s     r   __init__z_TextCompletionRequest.__init__+   	    	r   r!   c                 (    d| j                   d   dgS )Nuserpromptrolecontentr1   r$   s    r   r&   z#_TextCompletionRequest.get_messages.   s    DIIh,?@AAr   r(   c                 d    t        |      dk(  sJ |d   d   | j                  d<   | j                  S )N   r   r;   r8   )lenr2   r*   s     r   r+   z+_TextCompletionRequest.update_original_body2   s7    ?#q(((-a0;		(yyr   N	r   r   r   r4   r,   r-   r&   r   r+   r   r   r   r/   r/   *   s0    Bd4j BDJ 3 r   r/   c                   :    e Zd Zd Zdee   fdZdee   defdZy)_TextCompletionResponsec                     || _         y r#   r1   r3   s     r   r4   z _TextCompletionResponse.__init__9   r5   r   r!   c                 `    g }| j                   d   D ]  }|j                  d|d   d        |S )Nchoices	assistanttextr9   r2   appendr%   messageschoices      r   r&   z$_TextCompletionResponse.get_messages<   s6    ii	*FOO[VF^LM + r   r(   c                     t        |      t        | j                  d         k(  sJ t        | j                  d   |      D ]  \  }}|d   |d<    | j                  S )NrD   r;   rF   r>   r2   zipr%   r(   rK   prompt_messages       r   r+   z,_TextCompletionResponse.update_original_bodyC   s]    ?#s499Y+?'@@@@&)$))I*>&P"FN+I6F6N 'Q yyr   Nr?   r   r   r   rA   rA   8   s.    d4j DJ 3 r   rA   c                   :    e Zd Zd Zdee   fdZdee   defdZy)_ChatCompletionRequestc                     || _         y r#   r1   r3   s     r   r4   z_ChatCompletionRequest.__init__M   r5   r   r!   c                     g }| j                   d   D ]h  }|d   }|d   }t        |t              r|j                  ||d       t        |t              sB|D ]"  }|d   dk(  s|j                  ||d   d       $ j |S )NrJ   r:   r;   r9   typerF   )r2   
isinstancestrrH   r,   )r%   rJ   messager:   r;   content_parts         r   r&   z#_ChatCompletionRequest.get_messagesP   s    yy,G6?Di(G'3'' BC'4($+L#F+v5 ,vBV(WX %, - r   r(   c                    d}| j                   d   D ]X  }|d   }t        |t              r||   d   |d<   |dz  }t        |t              s9|D ]  }|d   dk(  s||   d   |d<   |dz  } Z t	        |      |k(  sJ | j                   S )Nr   rJ   r;   r=   rU   rF   )r2   rV   rW   r,   r>   )r%   r(   countrX   r;   rY   s         r   r+   z+_ChatCompletionRequest.update_original_body_   s    yy,Gi(G'3'%4U%;I%F	"
'4($+L#F+v5/>u/Ei/PV,
 %, - ?#u,,,yyr   Nr?   r   r   r   rR   rR   L   s.    d4j DJ 3 r   rR   c                   :    e Zd Zd Zdee   fdZdee   defdZy)_ChatCompletionResponsec                     || _         y r#   r1   r3   s     r   r4   z _ChatCompletionResponse.__init__r   r5   r   r!   c                 r    g }| j                   d   D ]"  }|j                  |d   d   |d   d   d       $ |S )NrD   rX   r:   r;   r9   rG   rI   s      r   r&   z$_ChatCompletionResponse.get_messagesu   sL    ii	*FOO"9-f5%i0; + r   r(   c                     t        |      t        | j                  d         k(  sJ t        | j                  d   |      D ]  \  }}|d   |d   d<    | j                  S )NrD   r;   rX   rM   rO   s       r   r+   z,_ChatCompletionResponse.update_original_body   sc    ?#s499Y+?'@@@@&)$))I*>&P"FN+9)+DF9i( 'Q yyr   Nr?   r   r   r   r]   r]   q   s.    d4j DJ 3 r   r]   r!   c                 p    |xxdk(  rnxdk(  rn n  t        |       S xdk(  rnxdk(  rn y  t        |       S )Ntext_completionatext_completion
completionacompletion)r/   rR   )r2   	call_types     r   _get_transformer_for_requestrg      s9    
3!33)$//M)  *)$//r   c                 f    | xt         d x\    t        |       S  t        d x\   t        |       S  y )Nr   )r   rA   r   r]   r1   s    r   _get_transformer_for_responseri      s8    
%#%*400 &_*400  r   c                        e Zd ZdZ	 	 	 	 ddedee   dee   dee   dee   f
 fdZded	ed
efdZe	de
dededefd       Ze	dede
defd       Zed
eed      fd       Z xZS )PangeaHandlerz
    Pangea AI Guardrail handler to interact with the Pangea AI Guard service.

    This class implements the necessary hooks to call the Pangea AI Guard API
    for input and output scanning based on the configured recipe.
    guardrail_namepangea_input_recipepangea_output_recipeapi_keyapi_basec                    t        t        j                        | _        |xs t        j
                  j                  d      | _        | j                  st        d      |xs# t        j
                  j                  d      xs d| _	        || _
        || _        | j                   d| _        t        | 8  dd|i| t        j                   d| d	| d
| j                          y)a  
        Initializes the PangeaHandler.

        Args:
            guardrail_name (str): The name of the guardrail instance.
            pangea_recipe (str): The Pangea recipe key to use for scanning.
            api_key (Optional[str]): The Pangea API key. Reads from PANGEA_API_KEY env var if None.
            api_base (Optional[str]): The Pangea API base URL. Reads from PANGEA_API_BASE env var or uses default if None.
            **kwargs: Additional arguments passed to the CustomGuardrail base class.
        )llm_providerPANGEA_API_KEYz_Pangea API Key not found. Set PANGEA_API_KEY environment variable or pass it in litellm_params.PANGEA_API_BASEz$https://ai-guard.aws.us.pangea.cloudz/v1/text/guardrl   z#Initialized Pangea Guardrail: name=z	, recipe=z, api_base=Nr   )r   r   GuardrailCallbackasync_handlerosenvirongetro   r   rp   rm   rn   guardrail_endpointsuperr4   r	   info)r%   rl   rm   rn   ro   rp   kwargs	__class__s          r   r4   zPangeaHandler.__init__   s    & 4-??
 B"**..1A"B||/q   6zz~~/065 	
 $7 $8!%)]]O>"B 	AA&A!!1.1AK^J__jkokxkxjyz	
r   payload	hook_namer!   c                   K   d| j                    dd}	 t        j                  d| d| j                   d|        | j                  j                  | j                  ||       d{   }|j                          |j                         }t        j                  d| d	|        |j                  d
i       j                  d      du rEt        j                  d| d|        t        dd| j                  |j                  d
      d      t        j                  d| d|j                  d
i       j                  d              |S 7 # t        $ r}|d}~wt        $ rl}t        j                  d| d| dt        |dd      xr t        |j                   dd              t        dd| j                  t#        |      d      |d}~ww xY ww)a  
        Makes the API call to the Pangea AI Guard endpoint.
        The function itself will raise an error in the case that a response
        should be blocked, but will return a list of redacted messages that the caller
        should act on.

        Args:
            payload (dict): The request payload.
            request_data (dict): Original request data (used for logging/headers).
            hook_name (str): Name of the hook calling this function (for logging).

        Raises:
            HTTPException: If the Pangea API returns a 'blocked: true' response.
            Exception: For other API call failures.

        Returns:
            list[dict]: The original response body
        zBearer zapplication/json)AuthorizationzContent-TypezPangea Guardrail (z): Calling endpoint z with payload: )urljsonheadersNz): Received response: resultblockedTz): Request blocked. Response: i  z Violated Pangea guardrail policy)errorrl   pangea_responsestatus_codedetailz): Request passed. Response: 	detectorsz): Error calling API: z. Response text: responserF     z)Error communicating with Pangea Guardrail)r   rl   	exception)ro   r	   debugrz   rv   postraise_for_statusr   ry   warningr   rl   r|   	Exceptionr   getattrr   rW   )r%   r   r   r   r   r   es          r   _call_pangea_guardz PangeaHandler._call_pangea_guard   s6    (  't||n5.
3	 &&$YK/CDD[D[C\\klsktu "//44++'7 5  H %%']]_F &&$YK/EfXN
 zz(B'++I6$>$,,(3QRXQYZ $ #!C*.*=*=+1::h+?  %))(3PQWQ[Q[\dfhQiQmQmnyQzP{| M9<  	G 	 &&$YK/EaSHYZabceoquZv  []  |C  DE  DN  DN  PV  X\  |]  Z^  _  H&*&9&9!$Q 	sI   GAE )E*C"E GE 	GEG&A'GGGuser_api_key_dictcachedatarf   c           	        K   t         j                  }| j                  ||      dur%t        j                  d| j
                   d       |S t        ||      }|s't        j                  d| j
                   d| d       y |j                         }|s$t        j                  d| j
                   d       y d	|d
}| j                  r| j                  |d<   | j                  |d       d {   }	t        || j
                         |	j                  di       j                  dg       }
	 |j                  |
      S 7 O# t        $ r*}t        dd| j
                  t!        |      d      |d }~ww xY ww)Nr   
event_typeT>Pangea Guardrail (async_pre_call_hook): Guardrail is disabled .z;Pangea Guardrail (async_pre_call_hook): Skipping guardrail z9 because we cannot determine type of request: call_type ''z because messages is empty.Fr   rJ   recipeasync_pre_call_hook)request_datarl   r   r(   r   z&Failed to update original request bodyr   rl   
exceptionsr   )r   pre_callshould_run_guardrailr	   r   rl   rg   r   r&   rm   r   r   ry   r+   r   r   rW   )r%   r   r   r   rf   r   transformerrJ   ai_guard_payloadai_guard_responser(   r   s               r   r   z!PangeaHandler.async_pre_call_hook  s     )11
$$$:$FdR &&PQUQdQdPeefg K24C ((MdNaNaMbKI;VWY ++- ((MdNaNaMb-.   
 ##)-)A)AX&"&"9"93#
 
 	3d.A.A	
 ,//"=AABSUWX
	33ODD
  	E&*&9&9"%a& 	s6   C+E5-D=.=E5,D? <E5?	E2%E--E22E5r   c           	        K   t         j                  }| j                  ||      dur%t        j                  d| j
                   d       |S t        |      }|s$t        j                  d| j
                   d       y|j                         }t        j                  d|        d	|d
}| j                  r| j                  |d<   | j                  |d       d{   }|j                  di       j                  dg       }		 |j                  |	      S 7 8# t        $ r*}
t        dd| j
                  t        |
      d      |
d}
~
ww xY ww)a)  
        Guardrail hook run after a successful LLM call (scans output).

        Args:
            data (dict): The original request data.
            user_api_key_dict (UserAPIKeyAuth): User API key details.
            response (LLMResponseTypes): The response object from the LLM call.
        r   Tr   r   zDPangea Guardrail (async_post_call_success_hook): Skipping guardrail z, because we cannot determine type of requestNzGOT MESSAGES: Fr   r   post_call_success_hookr   r(   r   z'Failed to update original response bodyr   r   )r   	post_callr   r	   r   rl   ri   r   r&   rn   r   ry   r+   r   r   rW   )r%   r   r   r   r   r   rJ   r   r   r(   r   s              r   async_post_call_success_hookz*PangeaHandler.async_post_call_success_hookZ  sq      )22
$$$:$FdR &&PQUQdQdPeefg K3H= ((VW[WjWjVk>? ++-$$~hZ%@A 
 $$)-)B)BX&"&"9"96#
 
 ,//"=AABSUWX
	33ODD
  	F&*&9&9"%a& 	s6   CED&ED E	E	%EE		Er   c                      ddl m}  | S )Nr   PangeaGuardrailConfigModel)5litellm.types.proxy.guardrails.guardrail_hooks.pangear   r   s    r   get_config_modelzPangeaHandler.get_config_model  s    	
 *)r   )NNNN)r   r   r   r   rW   r   r4   r-   r   r   r   r
   r   r   r   staticmethodr   r   __classcell__)r~   s   @r   rk   rk      s    .2.2!%"&*
*
 &c]*
 'sm	*

 #*
 3-*
XJ J J JX 8)8 8 	8
 8 8t 66 *6
 #6 6p *ht,B'CD * *r   rk   ))rw   typingr   r   r   r   r   fastapir   litellm._loggingr	   litellm.caching.dual_cacher
   %litellm.integrations.custom_guardrailr   r   &litellm.llms.custom_httpx.http_handlerr   r   litellm.proxy._typesr   )litellm.proxy.common_utils.callback_utilsr   litellm.types.guardrailsr   litellm.types.utilsr   r   r   3litellm.types.proxy.guardrails.guardrail_hooks.baser   r   r   r    r/   rA   rR   r]   rg   ri   rk   r   r   r   <module>r      s    	 ? ? ! 1 0 0 9 W WX	I 	8   (" "J 4Xl5K 8L+A z*O z*r   