o
    ưi                    @   s~  d Z ddlZddlZddl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mZ ddl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 ddlmZ ddl m!Z!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/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZA e Z-e+ ZBde
e	 de:fddZCe-jDddgee$ge:ddd ZEe-jDddgee$ge:ddd ZFG dd  d eZGe-jHd!dgd"ee$fd#eGd$e"fd%d&ZIG d'd( d(eZJe-jKd)dgd"ee$fd*eLd#eJd$e"fd+d,ZMe-jNd)dgd"ee$fd*eLd$e"fd-d.ZOd/ZPG d0d1 d1eZQG d2d3 d3eZRG d4d5 d5eZSG d6d7 d7eZTG d8d9 d9eZUe-jHd:dgeRd;ee$fd#eQd$e"fd<d=ZVd>edee	eLef  fd?d@ZWdAedeTfdBdCZXe-jDdDdgeUd;dddee$fdEeeL dFeeL dGeeL d$e"fdHdIZYe-jDdJdgeTd;ee$fd*eLd$e"fdKdLZZe-jHdMdgd"ee$fd*eLd$e"fdNdOZ[e-jHdPdgd"ee$fd*eLd$e"fdQdRZ\e-j]d)dgd"ee$fd*eLd#e<d$e"fdSdTZ^e-jDd)dgee$gdUe-jDdVdgee$gdUd*eLfdWdXZ_e-jDdYdgee$gdUdZd[ Z`e-jDd\dgee$gdUd]eLfd^d_Zae-jDd`dgee$gdUdadb Zbe-jHdcdgee$gdUd#e	eLeLf fdddeZcdfedeLfdgdhZddiede
eL fdjdkZedfedee
eL  fdldmZfdfedeLfdndoZgdfedee
eL  fdpdqZhdreLdfedeifdsdtZjdfedefdudvZkdwedfedxeLdyeide	eLef f
dzd{Zl	dd|ee d}emde	eLef fd~dZndee de	eLef fddZoe-jDddgee$gdUdd ZpG dd deZqG dd deZre-jHddgerd;ee$fd#eqd$e"fddZse-jHde2de-jHde2dee$fd#e1d$e"fddZte-ue. dS )z
CRUD ENDPOINTS FOR GUARDRAILS
    N)datetimetimezone)AnyDictListOptionalTypeTypeVarUnioncast)urlparse)	APIRouterDependsHTTPException)	BaseModel)verbose_proxy_logger)DEFAULT_MAX_RECURSE_DEPTH)CustomGuardrail)
safe_dumps)LitellmUserRolesUserAPIKeyAuth)user_api_key_auth)CustomCodeValidationErrorvalidate_custom_code)get_custom_code_primitives)GuardrailRegistry)router)PII_ENTITY_CATEGORIES_MAPApplyGuardrailRequestApplyGuardrailResponseBaseLitellmParamsBedrockGuardrailConfigModel	GuardrailGuardrailEventHooksGuardrailInfoResponseGuardrailUIAddGuardrailSettingsLakeraV2GuardrailConfigModelListGuardrailsResponseLitellmParamsPatchGuardrailRequest	PiiActionPiiEntityType(PresidioPresidioConfigModelUserInterfaceSupportedGuardrailIntegrations"ToolPermissionGuardrailConfigModelguardrails_configreturnc              	   C   s>   g }| D ]}| t|d|d|dd qt|dS )z=
    Helper function to get the guardrails list response
    guardrail_namelitellm_paramsguardrail_info)r1   r2   r3   
guardrails)appendr$   getr'   )r/   guardrail_configs	guardrail r:   c/home/app/Keep/.python/lib/python3.10/site-packages/litellm/proxy/guardrails/guardrail_endpoints.py_get_guardrails_list_response9   s   
r<   z/guardrails/listZ
Guardrails)tagsdependenciesresponse_modelc                     sD   ddl m}  | j}tttt  |d}|du rtg S t|S )ur  
    List the guardrails that are available on the proxy server

    👉 [Guardrail docs](https://docs.litellm.ai/docs/proxy/guardrails/quick_start)

    Example Request:
    ```bash
    curl -X GET "http://localhost:4000/guardrails/list" -H "Authorization: Bearer <your_api_key>"
    ```

    Example Response:
    ```json
    {
        "guardrails": [
            {
            "guardrail_name": "bedrock-pre-guard",
            "guardrail_info": {
                "params": [
                {
                    "name": "toxicity_score",
                    "type": "float",
                    "description": "Score between 0-1 indicating content toxicity level"
                },
                {
                    "name": "pii_detection",
                    "type": "boolean"
                }
                ]
            }
            }
        ]
    }
    ```
    r   )proxy_configr5   N)	litellm.proxy.proxy_serverr@   configr   r   listdictr7   r<   )r@   rB   Z_guardrails_configr:   r:   r;   list_guardrailsK   s   )rE   z/v2/guardrails/listc                     s  ddl m}  ddlm} ddlm} |du rtdddztj|dI dH }g }t	 }|D ]M}|
d	}t|tr@|jd
dn|pCi }| |ddd}	|	rTtdi |	nd}
|t|
d|
d|
|
d|
d|
ddd ||
d q.| }|D ]P}|
d|vr|
d	}t|tr|jd
dn|pi }| |ddd}|rtdi |nd}|t|
d|
d|t|
dpi dd ||
d qt|dW S  ty } ztd|  tdt|dd}~ww )u  
    List the guardrails that are available in the database using GuardrailRegistry

    👉 [Guardrail docs](https://docs.litellm.ai/docs/proxy/guardrails/quick_start)

    Example Request:
    ```bash
    curl -X GET "http://localhost:4000/v2/guardrails/list" -H "Authorization: Bearer <your_api_key>"
    ```

    Example Response:
    ```json
    {
        "guardrails": [
            {
                "guardrail_id": "123e4567-e89b-12d3-a456-426614174000",
                "guardrail_name": "my-bedrock-guard",
                "litellm_params": {
                    "guardrail": "bedrock",
                    "mode": "pre_call",
                    "guardrailIdentifier": "ff6ujrregl1q",
                    "guardrailVersion": "DRAFT",
                    "default_on": true
                },
                "guardrail_info": {
                    "description": "Bedrock content moderation guardrail"
                }
            }
        ]
    }
    ```
    r   _get_masked_valuesIN_MEMORY_GUARDRAIL_HANDLERprisma_clientN  Prisma client not initializedstatus_codedetailr2   TZexclude_none   Zunmasked_lengthZnumber_of_asterisksguardrail_idr1   r3   
created_at
updated_atdbrT   r1   r2   r3   rU   rV   guardrail_definition_locationrB   )rT   r1   r2   r3   rY   r4   z"Error getting guardrails from db: r:   )*litellm.litellm_core_utils.litellm_loggingrG   +litellm.proxy.guardrails.guardrail_registryrI   rA   rK   r   GUARDRAIL_REGISTRYZget_all_guardrails_from_dbsetr7   
isinstancer(   
model_dumpr    r6   r$   addZlist_in_memory_guardrailsrD   r'   	Exceptionr   	exceptionstr)rG   rI   rK   r5   r8   Zseen_guardrail_idsr9   r2   litellm_params_dictmasked_litellm_params_dictmasked_litellm_paramsZin_memory_guardrailsZin_memory_litellm_params_rawZin_memory_litellm_params_dictZmasked_in_memory_litellm_paramsZ%masked_in_memory_litellm_params_typeder:   r:   r;   list_guardrails_v2   s   '
	rh   c                   @      e Zd ZU eed< dS )CreateGuardrailRequestr9   N__name__
__module____qualname__r"   __annotations__r:   r:   r:   r;   rj         
 rj   z/guardrails)r=   requestuser_api_key_dictc           	         s&  ddl m} ddlm} |jtjkrtddd|du r#tdd	dzStj	| j
|d
I dH }|dd}|dd}z|jtt|d td| d| d W |W S  tyv } ztd| d| d|  W Y d}~|W S d}~ww  ty } ztd|  tdt|dd}~ww )u  
    Create a new guardrail

    👉 [Guardrail docs](https://docs.litellm.ai/docs/proxy/guardrails/quick_start)

    Example Request:
    ```bash
    curl -X POST "http://localhost:4000/guardrails" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "guardrail": {
                "guardrail_name": "my-bedrock-guard",
                "litellm_params": {
                    "guardrail": "bedrock",
                    "mode": "pre_call",
                    "guardrailIdentifier": "ff6ujrregl1q",
                    "guardrailVersion": "DRAFT",
                    "default_on": true
                },
                "guardrail_info": {
                    "description": "Bedrock content moderation guardrail"
                }
            }
        }'
    ```

    Example Response:
    ```json
    {
        "guardrail_id": "123e4567-e89b-12d3-a456-426614174000",
        "guardrail_name": "my-bedrock-guard",
        "litellm_params": {
            "guardrail": "bedrock",
            "mode": "pre_call",
            "guardrailIdentifier": "ff6ujrregl1q",
            "guardrailVersion": "DRAFT",
            "default_on": true
        },
        "guardrail_info": {
            "description": "Bedrock content moderation guardrail"
        },
        "created_at": "2023-11-09T12:34:56.789Z",
        "updated_at": "2023-11-09T12:34:56.789Z"
    }
    ```
    r   rH   rJ     *Admin access required to manage guardrailsrN   NrL   rM   )r9   rK   r1   UnknownrT   r9   z4Immediate sync: Successfully initialized guardrail '' (ID: )z0Immediate sync: Failed to initialize guardrail ') in memory: zError adding guardrail to db: )r[   rI   rA   rK   	user_roler   PROXY_ADMINr   r\   Zadd_guardrail_to_dbr9   r7   initialize_guardrailr   r"   r   infora   warningrb   rc   )	rq   rr   rI   rK   resultr1   rT   Z
init_errorrg   r:   r:   r;   create_guardrail   sH   7r   c                   @   ri   )UpdateGuardrailRequestr9   Nrk   r:   r:   r:   r;   r   \  rp   r   z/guardrails/{guardrail_id}rT   c           
         sX  ddl m} ddlm} |jtjkrtddd|du r#tdd	dzgtj	| |d
I dH }|du r<tdd|  ddtj
| |j|dI dH }|dd}z|j| tt|d td| d|  d W |W S  ty } ztd| d|  d|  W Y d}~|W S d}~ww  ty }	 z|	d}	~	w ty }	 ztdt|	dd}	~	ww )u  
    Update an existing guardrail

    👉 [Guardrail docs](https://docs.litellm.ai/docs/proxy/guardrails/quick_start)

    Example Request:
    ```bash
    curl -X PUT "http://localhost:4000/guardrails/123e4567-e89b-12d3-a456-426614174000" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "guardrail": {
                "guardrail_name": "updated-bedrock-guard",
                "litellm_params": {
                    "guardrail": "bedrock",
                    "mode": "pre_call",
                    "guardrailIdentifier": "ff6ujrregl1q",
                    "guardrailVersion": "1.0",
                    "default_on": true
                },
                "guardrail_info": {
                    "description": "Updated Bedrock content moderation guardrail"
                }
            }
        }'
    ```

    Example Response:
    ```json
    {
        "guardrail_id": "123e4567-e89b-12d3-a456-426614174000",
        "guardrail_name": "updated-bedrock-guard",
        "litellm_params": {
            "guardrail": "bedrock",
            "mode": "pre_call",
            "guardrailIdentifier": "ff6ujrregl1q",
            "guardrailVersion": "1.0",
            "default_on": true
        },
        "guardrail_info": {
            "description": "Updated Bedrock content moderation guardrail"
        },
        "created_at": "2023-11-09T12:34:56.789Z",
        "updated_at": "2023-11-09T13:45:12.345Z"
    }
    ```
    r   rH   rJ   rs   rt   rN   NrL   rM   rT   rK     Guardrail with ID 
 not foundrT   r9   rK   r1   ru   )rT   r9   0Immediate sync: Successfully updated guardrail 'rw   rx   "Immediate sync: Failed to update 'ry   )r[   rI   rA   rK   rz   r   r{   r   r\   get_guardrail_by_id_from_dbupdate_guardrail_in_dbr9   r7   Zupdate_in_memory_guardrailr   r"   r   r}   ra   r~   rc   )
rT   rq   rr   rI   rK   existing_guardrailr   r1   update_errorrg   r:   r:   r;   update_guardrail`  s\   8
r   c           	         sL  ddl m} ddlm} |jtjkrtddd|du r#tdd	dzatj	| |d
I dH }|du r<tdd|  ddtj
| |d
I dH }|dd}z|j| d td| d|  d W |W S  ty } ztd| d|  d|  W Y d}~|W S d}~ww  ty } z|d}~w ty } ztdt|dd}~ww )u  
    Delete a guardrail

    👉 [Guardrail docs](https://docs.litellm.ai/docs/proxy/guardrails/quick_start)

    Example Request:
    ```bash
    curl -X DELETE "http://localhost:4000/guardrails/123e4567-e89b-12d3-a456-426614174000" \
        -H "Authorization: Bearer <your_api_key>"
    ```

    Example Response:
    ```json
    {
        "message": "Guardrail 123e4567-e89b-12d3-a456-426614174000 deleted successfully"
    }
    ```
    r   rH   rJ   rs   rt   rN   NrL   rM   r   r   r   r   r1   ru   rT   z0Immediate sync: Successfully removed guardrail 'rw   z) from memoryz,Immediate sync: Failed to remove guardrail 'z) from memory: )r[   rI   rA   rK   rz   r   r{   r   r\   r   Zdelete_guardrail_from_dbr7   Zdelete_in_memory_guardrailr   r}   ra   r~   rc   )	rT   rr   rI   rK   r   r   r1   Zdelete_errorrg   r:   r:   r;   delete_guardrail  sX   r   Zgeneric_guardrail_apic                   @   sX   e Zd ZU dZeed< eeef ed< dZe	eeef  ed< deeef fddZ
dS )	RegisterGuardrailRequestzQRequest body for POST /guardrails/register. Follows Generic Guardrail API config.r1   r2   Nr3   r0   c                 C   s
   t | jS N)rD   r2   )selfr:   r:   r;   get_litellm_params_dict"  s   
z0RegisterGuardrailRequest.get_litellm_params_dict)rl   rm   rn   __doc__rc   ro   r   r   r3   r   r   r:   r:   r:   r;   r     s   
 r   c                   @   s6   e Zd ZU eed< eed< eed< dZee ed< dS )RegisterGuardrailResponserT   r1   statusNsubmitted_at)rl   rm   rn   rc   ro   r   r   r   r:   r:   r:   r;   r   &  s
   
 r   c                   @   s.   e Zd ZU eed< eed< eed< eed< dS )GuardrailSubmissionSummarytotalpending_reviewactiverejectedN)rl   rm   rn   intro   r:   r:   r:   r;   r   -  s
   
 r   c                   @   s   e Zd ZU eed< eed< eed< dZee ed< dZeed< dZ	ee
eef  ed< dZee
eef  ed	< dZee ed
< dZee ed< dZee ed< dZee ed< dZee ed< dZee ed< dS )GuardrailSubmissionItemrT   r1   r   Nteam_idFteam_guardrailr2   r3   submitted_by_user_idsubmitted_by_emailr   reviewed_atrU   rV   )rl   rm   rn   rc   ro   r   r   r   boolr2   r   r   r3   r   r   r   r   r   rU   rV   r:   r:   r:   r;   r   4  s   
 
r   c                   @   s"   e Zd ZU ee ed< eed< dS ) ListGuardrailSubmissionsResponsesubmissionssummaryN)rl   rm   rn   r   r   ro   r   r:   r:   r:   r;   r   F  s   
 r   z/guardrails/register)r=   r?   c              
      s  ddl m} |du rtddd|jstddd|  }|d	tkr/tdd
tdd|d}|s<tdddt|}|jdvrKtddd|j	sTtddd|d}|du rctdddz|j
jjd| jidI dH }|durtdd| jddW n! ty     ty } ztd| tdt|dd}~ww ttj}	t|}
t| jpi }|j|d< |j|d< d|d< t|}z#|j
jj| j|
|d|j|	|	|	ddI dH }t|j|j|j|jdW S  ty } ztd | tdt|dd}~ww )!a%  
    Register a guardrail for onboarding (team submission).

    Accepts a guardrail config in the
    [Generic Guardrail API](https://docs.litellm.ai/docs/adding_provider/generic_guardrail_api) format.
    The submission is stored with status `pending_review` until an admin approves it.
    r   rJ   NrL   rM   rN     zORegistration requires an API key associated with a team. Use a team-scoped key.r9   z.Only guardrails with litellm_params.guardrail=z are accepted for registrationapi_basez=litellm_params.api_base is required for generic_guardrail_api)httphttpsz5litellm_params.api_base must use http or https schemez5litellm_params.api_base must contain a valid hostnamemodez:litellm_params.mode is required (e.g. pre_call, post_call)r1   wherezGuardrail with name z already existsz,Error checking guardrail name uniqueness: %sr   r   Tr   r   )r1   r2   r3   r   r   r   rU   rV   )data)rT   r1   r   r   zError registering guardrail: %s) rA   rK   r   r   r   r7   GENERIC_GUARDRAIL_APIr   schemehostnamerW   litellm_guardrailstablefind_uniquer1   ra   r   rb   rc   r   nowr   utcr   rD   r3   user_idZ
user_emailcreater   rT   r   r   )rq   rr   rK   paramsr   parsedr   existingrg   r   Zlitellm_params_strr3   Zguardrail_info_strcreatedr:   r:   r;   register_guardrailK  s   





r   valuec                 C   sJ   | d u rd S t | tr| S t | tr#zt| W S  ty"   Y d S w d S r   )r^   rD   rc   jsonloadsra   r   r:   r:   r;   _parse_json_field  s   

r   rowc                 C   sl   t | jpi }| jd u}t| j| j| jpd| j|t | j||d|dt	| dd t	| dd | j
| jdS )Nr   r   r   r   r   )rT   r1   r   r   r   r2   r3   r   r   r   r   rU   rV   )r   r3   r   r   rT   r1   r   r2   r7   getattrrU   rV   )r   r3   r   r:   r:   r;   _row_to_submission_item  s"   


r   z/guardrails/submissionsr   r   searchc              
      sH  ddl m} |jtjkrtddd|du rtdddzl|jjjd	d
diiddidI dH }t	|}t
dd |D }t
dd |D }t
dd |D }	|}
r\fdd|
D }
rgfdd|
D }
|rv|   fdd|
D }
dd |
D }t|t||||	ddW S  ty } ztd| tdt|dd}~ww )aS  
    List team guardrail submissions (admin only). Returns only guardrails with a team_id.

    Status values: pending_review (team-registered, awaiting approval), active (approved), rejected.

    Optional filters:
    - status: pending_review | active | rejected
    - team_id: filter by specific team
    - search: name/description
    r   rJ   rs   Admin access requiredrN   NrL   rM   r   notrU   Zdesc)r   orderc                 s   "    | ]}|j pd dkrdV  qdS )r   r      Nr   .0rr:   r:   r;   	<genexpr>      z-list_guardrail_submissions.<locals>.<genexpr>c                 s   s"    | ]}|j pd d krdV  qdS )r   r   Nr   r   r:   r:   r;   r     r   c                 s   r   )r   r   r   Nr   r   r:   r:   r;   r     r   c                       g | ]	}|j  kr|qS r:   r   r   r   r:   r;   
<listcomp>      z.list_guardrail_submissions.<locals>.<listcomp>c                    r   r:   r   r   r   r:   r;   r     r   c                    sf   g | ]/} |j p	d  v s/t|jtr" t|jpi dd  v s/t|jtr1 |j v r|qS ) description)r1   lowerr^   r3   rD   rc   r7   r   )search_lowerr:   r;   r     s    


c                 S   s   g | ]}t |qS r:   )r   r   r:   r:   r;   r     s    )r   r   r   r   )r   r   z'Error listing guardrail submissions: %s)rA   rK   rz   r   r{   r   rW   r   Z	find_manylensumr   r   r   ra   r   rb   rc   )r   r   r   rr   rK   Zall_team_rowsr   r   active_countr   rowsitemsrg   r:   )r   r   r   r;   list_guardrail_submissions  s\   

	r   z&/guardrails/submissions/{guardrail_id}c              
      s   ddl m} |jtjkrtddd|du rtdddz|jjjd	| id
I dH }|du r5tdddt	|W S  tyA     t
yZ } ztd| tdt|dd}~ww )z5Get a single guardrail submission by id (admin only).r   rJ   rs   r   rN   NrL   rM   rT   r   r   Guardrail submission not foundz&Error getting guardrail submission: %s)rA   rK   rz   r   r{   r   rW   r   r   r   ra   r   rb   rc   )rT   rr   rK   r   rg   r:   r:   r;   get_guardrail_submission.  s,   

r   z./guardrails/submissions/{guardrail_id}/approvec              
      s  ddl m} ddlm} |jtjkrtddd|du r#tdd	dz|jj	j
d
| idI dH }|du r;tddd|jdkrKtdd|j ddttj}|jj	jd
| id||ddI dH  t|j}t|j}|sutddd|j|j||p}i d}z|jtt|d td|j|  W n% ty }	 ztd| |	 | ddd|	 ddW  Y d}	~	W S d}	~	ww | dddW S  ty     ty }
 ztd|
 tdt|
dd}
~
ww ) zcApprove a pending guardrail submission: set status to active and initialize in memory (admin only).r   rH   rJ   rs   r   rN   NrL   rM   rT   r   r   r   r   r   (Guardrail is not pending review (status=rx   r   r   r   rV   r   r   z.Guardrail litellm_params is missing or invalidrT   r1   r2   r3   rv   z8Approved guardrail %s (ID: %s) and initialized in memoryz8Failed to initialize approved guardrail %s in memory: %szGuardrail approvedz@Guardrail was marked active but failed to initialize in memory: z.. It will be picked up on the next sync cycle.)rT   r   messager~   rT   r   r   z(Error approving guardrail submission: %s)r[   rI   rA   rK   rz   r   r{   r   rW   r   r   r   r   r   r   r   updater   r2   r3   rT   r1   r|   r   r"   r   r}   ra   r~   rb   rc   )rT   rr   rI   rK   r   r   r2   r3   Zguardrail_dictZinit_errrg   r:   r:   r;   approve_guardrail_submissionP  s   	




r   z-/guardrails/submissions/{guardrail_id}/rejectc              
      s
  ddl m} |jtjkrtddd|du rtdddzF|jjjd	| id
I dH }|du r5tddd|j	dkrEtdd|j	 ddt
tj}|jjjd	| id||ddI dH  | dddW S  tyk     ty } ztd| tdt|dd}~ww )z+Reject a guardrail submission (admin only).r   rJ   rs   r   rN   NrL   rM   rT   r   r   r   r   r   r   rx   r   r   r   zGuardrail rejectedr   z(Error rejecting guardrail submission: %s)rA   rK   rz   r   r{   r   rW   r   r   r   r   r   r   r   r   ra   r   rb   rc   )rT   rr   rK   r   r   rg   r:   r:   r;   reject_guardrail_submission  sF   	

r   c                    s  ddl m} ddlm} |jtjkrtddd|du r#tdd	dztj	| |d
I dH }|du r<tdd|  dd|j
durD|j
n|d}tdi t|di }|jdurt|jjdd}|jdd}	|	| tdi |	}|jdur||jn|di }
t| |pd||
d}tj| ||dI dH }|dd}z|j|d td| d|  d W |W S  ty } ztd| d|  d|  W Y d}~|W S d}~ww  ty } z|d}~w ty } ztd|  tdt|dd}~ww )u  
    Partially update an existing guardrail

    👉 [Guardrail docs](https://docs.litellm.ai/docs/proxy/guardrails/quick_start)

    This endpoint allows updating specific fields of a guardrail without sending the entire object.
    Only the following fields can be updated:
    - guardrail_name: The name of the guardrail
    - default_on: Whether the guardrail is enabled by default
    - guardrail_info: Additional information about the guardrail

    Example Request:
    ```bash
    curl -X PATCH "http://localhost:4000/guardrails/123e4567-e89b-12d3-a456-426614174000" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "guardrail_name": "updated-name",
            "default_on": true,
            "guardrail_info": {
                "description": "Updated description"
            }
        }'
    ```

    Example Response:
    ```json
    {
        "guardrail_id": "123e4567-e89b-12d3-a456-426614174000",
        "guardrail_name": "updated-name",
        "litellm_params": {
            "guardrail": "bedrock",
            "mode": "pre_call",
            "guardrailIdentifier": "ff6ujrregl1q",
            "guardrailVersion": "DRAFT",
            "default_on": true
        },
        "guardrail_info": {
            "description": "Updated description"
        },
        "created_at": "2023-11-09T12:34:56.789Z",
        "updated_at": "2023-11-09T14:22:33.456Z"
    }
    ```
    r   rH   rJ   rs   rt   rN   NrL   rM   r   r   r   r   r1   r2   T)Zexclude_unsetr3   r   r   r   ru   rv   r   rw   rx   r   ry   zError updating guardrail: r:   )r[   rI   rA   rK   rz   r   r{   r   r\   r   r1   r7   r(   rD   r2   r_   r   r3   r"   r   Zsync_guardrail_from_dbr   r}   ra   r~   rb   rc   )rT   rq   rr   rI   rK   r   r1   r2   Zrequested_litellm_paramsrd   r3   r9   r   r   rg   r:   r:   r;   patch_guardrail  s   6




r   )r=   r>   z/guardrails/{guardrail_id}/infoc              
      sd  ddl m} ddlm} ddlm} ddlm} |du r#tddd	zm|j	}t
j| |d
I dH }|du r>|j| d}|j}|du rLtdd|  dd	|d}t|tr\|jddn|p_i }||ddd}	|	rptdi |	nd}
t|d|d|
t|dpi |d|d|dW S  ty } z|d}~w ty } ztdt|d	d}~ww )u  
    Get detailed information about a specific guardrail by ID

    👉 [Guardrail docs](https://docs.litellm.ai/docs/proxy/guardrails/quick_start)

    Example Request:
    ```bash
    curl -X GET "http://localhost:4000/guardrails/123e4567-e89b-12d3-a456-426614174000/info" \
        -H "Authorization: Bearer <your_api_key>"
    ```

    Example Response:
    ```json
    {
        "guardrail_id": "123e4567-e89b-12d3-a456-426614174000",
        "guardrail_name": "my-bedrock-guard",
        "litellm_params": {
            "guardrail": "bedrock",
            "mode": "pre_call",
            "guardrailIdentifier": "ff6ujrregl1q",
            "guardrailVersion": "DRAFT",
            "default_on": true
        },
        "guardrail_info": {
            "description": "Bedrock content moderation guardrail"
        },
        "created_at": "2023-11-09T12:34:56.789Z",
        "updated_at": "2023-11-09T12:34:56.789Z"
    }
    ```
    r   rF   rH   rJ   )GUARDRAIL_DEFINITION_LOCATIONNrL   rM   rN   r   r   r   r   r   r2   TrQ   rR   rS   rT   r1   r3   rU   rV   rX   r:   )rZ   rG   r[   rI   rA   rK   litellm.types.guardrailsr   r   ZDBr\   r   Zget_guardrail_by_idZCONFIGr7   r^   r(   r_   r    r$   rD   ra   rc   )rT   rG   rI   rK   r   rY   r   r2   Zresult_litellm_params_dictre   rf   rg   r:   r:   r;   get_guardrail_info`  sp   +	r   z%/guardrails/ui/add_guardrail_settingsc               
      s   ddl m} m}m} g }t D ]\}}||jdd |D d qtdd t	D dd t
D dd tD || t|  d	d
g| ddS )z
    Get the UI settings for the guardrails

    Returns:
    - Supported entities for guardrails
    - Supported modes for guardrails
    - PII entity categories for UI organization
    - Content filter settings (patterns and categories)
    r   )PATTERN_CATEGORIES get_available_content_categoriesget_pattern_metadatac                 S      g | ]}|j qS r:   r   r   entityr:   r:   r;   r         z-get_guardrail_ui_settings.<locals>.<listcomp>)categoryentitiesc                 S   r   r:   r   r   r:   r:   r;   r     r   c                 S   r   r:   r   )r   actionr:   r:   r;   r     r   c                 S   r   r:   r   )r   r   r:   r:   r;   r     r   BLOCKMASK)Zprebuilt_patternsZpattern_categoriessupported_actionsZcontent_categories)Zsupported_entitiesr   Zsupported_modesZpii_entity_categoriesZcontent_filter_settings)ZHlitellm.proxy.guardrails.guardrail_hooks.litellm_content_filter.patternsr   r   r   r   r   r6   r   r%   r+   r*   r#   rC   keys)r   r   r   Zcategory_mapsr   r   r:   r:   r;   get_guardrail_ui_settings  s(   
r   z,/guardrails/ui/category_yaml/{category_name}category_namec           
   
      s  ddl }|j|jtddd}|j||  d}|j||  d}d}d}|j|r5|}d}n|j|r@|}d	}n
td
d|  ddz t|d}| }W d   n1 s_w   Y  | ||dW S  t	y }	 ztddt
|	 dd}	~	ww )a  
    Get the YAML or JSON content for a specific content filter category.

    Args:
        category_name: The name of the category (e.g., "bias_gender", "harmful_self_harm")

    Returns:
        The raw YAML or JSON content of the category file with file type indicator
    r   Nguardrail_hookslitellm_content_filter
categoriesz.yamlz.jsonyamlr   r   zCategory file not found: z (tried .yaml and .json)rN   r   )r   Zyaml_content	file_typerL   zError reading category file: )ospathjoindirname__file__existsr   openreadra   rc   )
r   r  Zcategories_dirZ	yaml_pathZ	json_pathZcategory_file_pathr  fcontentrg   r:   r:   r;   get_category_yaml  sH   


r  z/guardrails/ui/major_airlinesc               
      s   ddl } | j| jtdddd}| j|stddd	z%t|d
dd}ddl}|	|}W d   n1 s;w   Y  d|iW S  t
y\ } ztddt| d	|d}~ww )z
    Get the major airlines list from IATA (competitor intent, airline type).
    Returns airline id, match variants (pipe-separated), and tags.
    r   Nr   r   Zcompetitor_intentzmajor_airlines.jsonr   zmajor_airlines.json not foundrN   r   zutf-8)encodingairlinesrL   z#Error reading major_airlines.json: )r  r  r  r  r  r	  r   r
  r   loadra   rc   )r  Zairlines_pathr  r   r  rg   r:   r:   r;   get_major_airlines0  s8   


r  z'/guardrails/validate_blocked_words_filec           	   
      s  ddl }z| dd}|sdddW S ||}t|tr"d|vr(dd	dW S |d }t|ts7dd
dW S g }t|D ]g\}}t|tsP|d| d q=d|vr^|d| d nt|d tsn|d| d d|vr||d| d n|d dvr|d| d|d  d d|v rt|d ts|d| d q=|rd|dW S ddt	| ddW S  |j
y } zddt| dW  Y d}~S d}~w ty } ztd ddt| dW  Y d}~S d}~ww )a  
    Validate a blocked_words YAML file content.

    Args:
        request: Dictionary with 'file_content' key containing the YAML string

    Returns:
        Dictionary with 'valid' boolean and either 'message'/'errors' depending on result

    Example Request:
    ```json
    {
        "file_content": "blocked_words:\n  - keyword: \"test\"\n    action: \"BLOCK\""
    }
    ```

    Example Success Response:
    ```json
    {
        "valid": true,
        "message": "Valid YAML file with 2 blocked words"
    }
    ```

    Example Error Response:
    ```json
    {
        "valid": false,
        "errors": ["Entry 0: missing 'action' field"]
    }
    ```
    r   Nfile_contentr   FzNo file content provided)validerrorZblocked_wordszAInvalid format: file must contain 'blocked_words' key with a listz'blocked_words' must be a listzEntry z: must be an objectkeywordz: missing 'keyword' fieldz: 'keyword' must be a stringr   z: missing 'action' field)r   r   z): action must be 'BLOCK' or 'MASK', got ''r   z : 'description' must be a string)r  errorsTzValid YAML file with z blocked word(s))r  r   zInvalid YAML syntax: z#Error validating blocked words filezValidation error: )r  r7   Z	safe_loadr^   rD   rC   	enumerater6   rc   r   Z	YAMLErrorra   r   rb   )	rq   r  r  r   Zblocked_words_listr  idxZ	word_datarg   r:   r:   r;   validate_blocked_words_fileT  s^   &



 
 r  field_annotationc                 C   s   t | dr| jtu rt | dr| j}dd |D }|r|d } t | dr+| jtu r+dS t | dr7| jtu r7dS t | drPt | drP| j}t |drP|jd	krPd
S | tu rVdS | tu r\dS | t	u rbdS | t
u rhdS | tu rndS | tu rtdS dS )zG
    Convert a Python type annotation to a UI-friendly type string
    
__origin____args__c                 S      g | ]
}|t d ur|qS r   typer   argr:   r:   r;   r         z3_get_field_type_from_annotation.<locals>.<listcomp>r   arrayrD   rl   Literalselectstringnumberbooleanobject)hasattrr  r
   r  rC   rD   rl   rc   r   floatr   )r  argsnon_none_argsoriginr:   r:   r;   _get_field_type_from_annotation  s@   
r1  
annotationc                 C   s<   t | drt | dr| j}t |dr|jdkrt| jS g S )z?
    Extract literal values from a Literal type annotation
    r  r  rl   r&  )r,  r  rl   rC   r  )r2  r0  r:   r:   r;   _extract_literal_values  s
   
r3  c                 C   D   t | dr | jtu r t | dr | j}t|dkr |d }t|S dS )z>
    Extract key options from Dict[Literal[...], T] types
    r  r     r   N)r,  r  rD   r  r   r3  )r  r.  Zkey_typer:   r:   r;   _get_dict_key_options     
r6  c                 C   r4  )z2
    Get the value type from Dict[K, V] types
    r  r  r5  r   r(  )r,  r  rD   r  r   r1  )r  r.  
value_typer:   r:   r;   _get_dict_value_type  r7  r9  c                 C   r4  )z?
    Extract element options from List[Literal[...]] types
    r  r  r   r   N)r,  r  rC   r  r   r3  )r  r.  Zelement_typer:   r:   r;   _get_list_element_options  r7  r:  
field_namec                 C   s   | dkrdS |du rdS t |tst|dr|jtu rdS t|dr)|jdv r)dS t|drAd	d
 |jD }|rAt |d trAdS dS )zOCheck if optional_params field should be skipped (not meaningfully overridden).Zoptional_paramsFNTr  rl   )Tr	   r  c                 S   r  r   r   r"  r:   r:   r;   r   9  s    z0_should_skip_optional_params.<locals>.<listcomp>r   )r^   r	   r,  r  rl   r  )r;  r  r/  r:   r:   r;   _should_skip_optional_params!  s$   


r=  c                 C   sB   t | dr| jtu rt | dr| j}dd |D }|r|d S | S )z-Unwrap Optional types to get the actual type.r  r  c                 S   r  r   r   r"  r:   r:   r;   r   K  r$  z)_unwrap_optional_type.<locals>.<listcomp>r   )r,  r  r
   r  )r  r.  r/  r:   r:   r;   _unwrap_optional_typeB  s   
r>  fieldr   requiredc                 C   s*  t |}t| di }|rd|v r|d }t|dr|jn|}n
|r)d|v r)|d }|||d}|dkrFt|}|r=||d< t|}	|	|d< n|d	krXt|}
|
rX|
|d
< d|d< |red
|v re|d
 |d
< n|dkrst|}|rs||d
< | jdur| jdur| j|d< |rdD ]}||v r|| ||< q|S )z-Build field dictionary for non-nested fields.Zjson_schema_extraui_typer   r!  )r   r@  r!  rD   dict_key_optionsdict_value_typer%  optionsZmultiselectr'  N.default_value)minmaxsteprE  )	r1  r   r,  r   r6  r9  r:  r3  default)r?  r  r   r@  Z
field_typeZfield_json_schema_extrarA  Z
field_dictrB  rC  Zlist_element_optionsZliteral_optionskeyr:   r:   r;   _build_field_dictQ  sH   

rK  modeldepthc           
      C   s   |t krtddt  ddi }| j D ]Q\}}|j}t||dr#q|d u r(qt|d}|jp1|}| }t	
|oCt|toC|tu}|r\tttt ||d }	||d|	d	||< qt||||d
||< q|S )Nr   zMax depth of z` exceeded while processing model fields. Please check the model structure for excessive nesting.rN   )r;  r  )r  r   nested)r   r@  r!  fields)r?  r  r   r@  )r   r   Zmodel_fieldsr   r2  r=  r>  r   Zis_requiredinspectisclass
issubclassr   _extract_fields_recursiver   r   rK  )
rL  rM  rO  r;  r?  r  r   r@  Zis_basemodel_subclassZnested_fieldsr:   r:   r;   rS    sL   



rS  model_classc                 C   s   t | ddS )zO
    Get the fields from a Pydantic model as a nested dictionary structure
    r   )rM  )rS  )rT  r:   r:   r;   _get_fields_from_model  s   rU  z'/guardrails/ui/provider_specific_paramsc                     s   t t} t t}t t}t t}t |d< tjj| tj	j|tj
j|tjj|i}ddlm} | D ]\}}| }|rMt |}	| }
|
|	d< |	||< q3|S )a  
    Get provider-specific parameters for different guardrail types.

    Returns a dictionary mapping guardrail providers to their specific parameters,
    including parameter names, descriptions, and whether they are required.

    Example Response:
    ```json
    {
        "bedrock": {
            "guardrailIdentifier": {
                "description": "The ID of your guardrail on Bedrock",
                "required": true,
                "type": null
            },
            "guardrailVersion": {
                "description": "The version of your Bedrock guardrail (e.g., DRAFT or version number)",
                "required": true,
                "type": null
            }
        },
        "azure_content_safety_text_moderation": {
            "api_key": {
                "description": "API key for the Azure Content Safety Text Moderation guardrail",
                "required": false,
                "type": null
            },
            "optional_params": {
                "description": "Optional parameters for the Azure Content Safety Text Moderation guardrail",
                "required": true,
                "type": "nested",
                "fields": {
                    "severity_threshold": {
                        "description": "Severity threshold for the Azure Content Safety Text Moderation guardrail across all categories",
                        "required": false,
                        "type": null
                    },
                    "categories": {
                        "description": "Categories to scan for the Azure Content Safety Text Moderation guardrail",
                        "required": false,
                        "type": "multiselect",
                        "options": ["Hate", "SelfHarm", "Sexual", "Violence"],
                        "default_value": None
                    }
                }
            }
        }
    }
    ```
    ui_friendly_namer   )guardrail_class_registry)rU  r!   r,   r&   r.   rV  r-   ZBEDROCKr   ZPRESIDIOZ	LAKERA_V2ZTOOL_PERMISSIONr[   rW  r   Zget_config_model)Zbedrock_fieldsZpresidio_fieldsZlakera_v2_fieldsZtool_permission_fieldsZprovider_paramsrW  r1   Zguardrail_classZguardrail_config_modelrO  rV  r:   r:   r;   get_provider_specific_params  s,   9rX  c                   @   sT   e Zd ZU dZeed< 	 eeef ed< 	 dZeed< 	 dZ	e
eeef  ed< dS )TestCustomCodeGuardrailRequestz1Request model for testing custom code guardrails.custom_code
test_inputrq   
input_typeNrequest_data)rl   rm   rn   r   rc   ro   r   r   r\  r]  r   r:   r:   r:   r;   rY  0  s   
 rY  c                   @   sX   e Zd ZU dZeed< 	 dZeee	e
f  ed< 	 dZee	 ed< 	 dZee	 ed< dS )TestCustomCodeGuardrailResponsez2Response model for testing custom code guardrails.successNr   r  
error_type)rl   rm   rn   r   r   ro   r   r   r   rc   r   r  r`  r:   r:   r:   r;   r^  @  s   
 r^  z/guardrails/test_custom_codec           
   
      s  |j tjkrtdddd}zFztj W n ty4 } ztdt|ddW  Y d}~W S d}~ww t	 
 }i |d	< zttjd
d| W n9 tyg } ztdd| ddW  Y d}~W S d}~w ty } ztdd| ddW  Y d}~W S d}~ww d|vrtddddW S |d  t stddddW S jdvrg d< jpi }|dd|d|d|d|di d fdd}zHtjjdd6}||}z|j|d}	W n  tjjy   tdd| dd d Y W  d   W W S w W d   n	1 sw   Y  W n ty8 } ztdd!| d dW  Y d}~W S d}~ww t|	tsPtd"d#d$t|	j d%d&d'W S td"|	d'W S  ty{ } ztd(|  tdd)| d dW  Y d}~S d}~ww )*u  
    Test custom code guardrail logic without creating a guardrail.

    This endpoint allows admins to experiment with custom code guardrails by:
    1. Compiling the provided code in a sandbox
    2. Executing the apply_guardrail function with test input
    3. Returning the result (allow/block/modify)

    👉 [Custom Code Guardrail docs](https://docs.litellm.ai/docs/proxy/guardrails/custom_code_guardrail)

    Example Request:
    ```bash
    curl -X POST "http://localhost:4000/guardrails/test_custom_code" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "custom_code": "def apply_guardrail(inputs, request_data, input_type):\n    for text in inputs[\"texts\"]:\n        if regex_match(text, r\"\\d{3}-\\d{2}-\\d{4}\"):\n            return block(\"SSN detected\")\n    return allow()",
            "test_input": {
                "texts": ["My SSN is 123-45-6789"]
            },
            "input_type": "request"
        }'
    ```

    Example Success Response (blocked):
    ```json
    {
        "success": true,
        "result": {
            "action": "block",
            "reason": "SSN detected"
        },
        "error": null,
        "error_type": null
    }
    ```

    Example Success Response (allowed):
    ```json
    {
        "success": true,
        "result": {
            "action": "allow"
        },
        "error": null,
        "error_type": null
    }
    ```

    Example Success Response (modified):
    ```json
    {
        "success": true,
        "result": {
            "action": "modify",
            "texts": ["My SSN is [REDACTED]"]
        },
        "error": null,
        "error_type": null
    }
    ```

    Example Error Response (compilation error):
    ```json
    {
        "success": false,
        "result": null,
        "error": "Syntax error in custom code: invalid syntax (<guardrail>, line 1)",
        "error_type": "compilation"
    }
    ```
    rs   z4Admin access required to test custom code guardrailsrN      FZcompilation)r_  r  r`  N__builtins__z<guardrail>execzSyntax error in custom code: zFailed to compile custom code: apply_guardrailz|Custom code must define an 'apply_guardrail' function. Expected signature: apply_guardrail(inputs, request_data, input_type)z-'apply_guardrail' must be a callable functiontextsrL  z
test-modelr   r   end_user_idmetadata)rL  r   r   rf  rg  c                      s    j S r   )r\  r:   Zapply_fnrq   Zsafe_request_dataZtest_inputsr:   r;   execute_guardrail  s   z5test_custom_code_guardrail.<locals>.execute_guardrailr   )max_workers)timeoutz)Execution timeout: code took longer than z secondsZ	executionzExecution error: TZallowzExpected dict result, got z. Treating as allow.)r   r~   )r_  r   z%Error testing custom code guardrail: zUnexpected error: )rz   r   r{   r   r   rZ  r   r^  rc   r   copyrc  compileSyntaxErrorra   callabler[  r]  r7   
concurrentfuturesThreadPoolExecutorsubmitr   TimeoutErrorr^   rD   r!  rl   r   rb   )
rq   rr   ZEXECUTION_TIMEOUT_SECONDSrg   Zexec_globalsZmock_request_datari  executorfuturer   r:   rh  r;   test_custom_code_guardrailP  s   R







rw  z/guardrails/apply_guardrail)r?   z/apply_guardrailc              
      s   ddl m} z;tj| jd}|du rtdd| j dd|jd	| jgii d
dI dH }|d	g }t	|r=|d dW S | jdW S  t
yR } z||d}~ww )z
    Apply a guardrail to text input and return the processed result.

    This endpoint allows testing guardrails by applying them to custom text inputs.
    r   )handle_exception_on_proxy)r1   Nr   zGuardrail 'zM' not found. Please ensure the guardrail is configured in your LiteLLM proxy.rN   re  rq   )Zinputsr]  r\  )response_text)Zlitellm.proxy.utilsrx  r\   Z"get_initialized_guardrail_callbackr1   r   rd  textr7   r   ra   )rq   rr   rx  Zactive_guardrailZguardrailed_inputsry  rg   r:   r:   r;   rd    s6   

rd  )r   )vr   concurrent.futuresrp  rP  r   r   r   typingr   r   r   r   r   r	   r
   r   urllib.parser   Zfastapir   r   r   Zpydanticr   Zlitellm._loggingr   Zlitellm.constantsr   Z%litellm.integrations.custom_guardrailr   Z*litellm.litellm_core_utils.safe_json_dumpsr   Zlitellm.proxy._typesr   r   Z$litellm.proxy.auth.user_api_key_authr   ZClitellm.proxy.guardrails.guardrail_hooks.custom_code.code_validatorr   r   Z?litellm.proxy.guardrails.guardrail_hooks.custom_code.primitivesr   r[   r   Z(litellm.proxy.guardrails.usage_endpointsr   Zguardrails_usage_routerr   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r\   r<   r7   rE   rh   rj   postr   r   putrc   r   deleter   r   r   r   r   r   r   r   r   r   r   r   r   r   patchr   r   r   r  r  r  r1  r3  r6  r9  r:  r   r=  r>  rK  r   rS  rU  rX  rY  r^  rw  rd  Zinclude_routerr:   r:   r:   r;   <module>   s   (P

/
uYfHgQR, ]
(7
Z3!

C

=
T F&