Spaces:
Configuration error
Configuration error
""" | |
CRUD ENDPOINTS FOR GUARDRAILS | |
""" | |
from typing import Any, Dict, List, Optional, Type, cast | |
from fastapi import APIRouter, Depends, HTTPException | |
from pydantic import BaseModel | |
from litellm._logging import verbose_proxy_logger | |
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth | |
from litellm.proxy.guardrails.guardrail_registry import GuardrailRegistry | |
from litellm.types.guardrails import ( | |
PII_ENTITY_CATEGORIES_MAP, | |
BedrockGuardrailConfigModel, | |
Guardrail, | |
GuardrailEventHooks, | |
GuardrailInfoResponse, | |
GuardrailParamUITypes, | |
GuardrailUIAddGuardrailSettings, | |
LakeraV2GuardrailConfigModel, | |
ListGuardrailsResponse, | |
LitellmParams, | |
PatchGuardrailRequest, | |
PiiAction, | |
PiiEntityType, | |
PresidioPresidioConfigModelUserInterface, | |
SupportedGuardrailIntegrations, | |
) | |
#### GUARDRAILS ENDPOINTS #### | |
router = APIRouter() | |
GUARDRAIL_REGISTRY = GuardrailRegistry() | |
def _get_guardrails_list_response( | |
guardrails_config: List[Dict], | |
) -> ListGuardrailsResponse: | |
""" | |
Helper function to get the guardrails list response | |
""" | |
guardrail_configs: List[GuardrailInfoResponse] = [] | |
for guardrail in guardrails_config: | |
guardrail_configs.append( | |
GuardrailInfoResponse( | |
guardrail_name=guardrail.get("guardrail_name"), | |
litellm_params=guardrail.get("litellm_params"), | |
guardrail_info=guardrail.get("guardrail_info"), | |
) | |
) | |
return ListGuardrailsResponse(guardrails=guardrail_configs) | |
async def list_guardrails(): | |
""" | |
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" | |
} | |
] | |
} | |
} | |
] | |
} | |
``` | |
""" | |
from litellm.proxy.proxy_server import proxy_config | |
config = proxy_config.config | |
_guardrails_config = cast(Optional[list[dict]], config.get("guardrails")) | |
if _guardrails_config is None: | |
return _get_guardrails_list_response([]) | |
return _get_guardrails_list_response(_guardrails_config) | |
async def list_guardrails_v2(): | |
""" | |
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" | |
} | |
} | |
] | |
} | |
``` | |
""" | |
from litellm.proxy.guardrails.guardrail_registry import IN_MEMORY_GUARDRAIL_HANDLER | |
from litellm.proxy.proxy_server import prisma_client | |
if prisma_client is None: | |
raise HTTPException(status_code=500, detail="Prisma client not initialized") | |
try: | |
guardrails = await GUARDRAIL_REGISTRY.get_all_guardrails_from_db( | |
prisma_client=prisma_client | |
) | |
guardrail_configs: List[GuardrailInfoResponse] = [] | |
seen_guardrail_ids = set() | |
for guardrail in guardrails: | |
guardrail_configs.append( | |
GuardrailInfoResponse( | |
guardrail_id=guardrail.get("guardrail_id"), | |
guardrail_name=guardrail.get("guardrail_name"), | |
litellm_params=guardrail.get("litellm_params"), | |
guardrail_info=guardrail.get("guardrail_info"), | |
created_at=guardrail.get("created_at"), | |
updated_at=guardrail.get("updated_at"), | |
guardrail_definition_location="db", | |
) | |
) | |
seen_guardrail_ids.add(guardrail.get("guardrail_id")) | |
# get guardrails initialized on litellm config.yaml | |
in_memory_guardrails = IN_MEMORY_GUARDRAIL_HANDLER.list_in_memory_guardrails() | |
for guardrail in in_memory_guardrails: | |
# only add guardrails that are not in DB guardrail list already | |
if guardrail.get("guardrail_id") not in seen_guardrail_ids: | |
guardrail_configs.append( | |
GuardrailInfoResponse( | |
guardrail_id=guardrail.get("guardrail_id"), | |
guardrail_name=guardrail.get("guardrail_name"), | |
litellm_params=dict(guardrail.get("litellm_params") or {}), | |
guardrail_info=dict(guardrail.get("guardrail_info") or {}), | |
guardrail_definition_location="config", | |
) | |
) | |
seen_guardrail_ids.add(guardrail.get("guardrail_id")) | |
return ListGuardrailsResponse(guardrails=guardrail_configs) | |
except Exception as e: | |
verbose_proxy_logger.exception(f"Error getting guardrails from db: {e}") | |
raise HTTPException(status_code=500, detail=str(e)) | |
class CreateGuardrailRequest(BaseModel): | |
guardrail: Guardrail | |
async def create_guardrail(request: CreateGuardrailRequest): | |
""" | |
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" | |
} | |
``` | |
""" | |
from litellm.proxy.proxy_server import prisma_client | |
if prisma_client is None: | |
raise HTTPException(status_code=500, detail="Prisma client not initialized") | |
try: | |
result = await GUARDRAIL_REGISTRY.add_guardrail_to_db( | |
guardrail=request.guardrail, prisma_client=prisma_client | |
) | |
return result | |
except Exception as e: | |
verbose_proxy_logger.exception(f"Error adding guardrail to db: {e}") | |
raise HTTPException(status_code=500, detail=str(e)) | |
async def get_guardrail(guardrail_id: str): | |
""" | |
Get a 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" \\ | |
-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" | |
} | |
``` | |
""" | |
from litellm.proxy.proxy_server import prisma_client | |
if prisma_client is None: | |
raise HTTPException(status_code=500, detail="Prisma client not initialized") | |
try: | |
result = await GUARDRAIL_REGISTRY.get_guardrail_by_id_from_db( | |
guardrail_id=guardrail_id, prisma_client=prisma_client | |
) | |
if result is None: | |
raise HTTPException( | |
status_code=404, detail=f"Guardrail with ID {guardrail_id} not found" | |
) | |
return result | |
except HTTPException as e: | |
raise e | |
except Exception as e: | |
raise HTTPException(status_code=500, detail=str(e)) | |
class UpdateGuardrailRequest(BaseModel): | |
guardrail: Guardrail | |
async def update_guardrail(guardrail_id: str, request: UpdateGuardrailRequest): | |
""" | |
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" | |
} | |
``` | |
""" | |
from litellm.proxy.proxy_server import prisma_client | |
if prisma_client is None: | |
raise HTTPException(status_code=500, detail="Prisma client not initialized") | |
try: | |
# Check if guardrail exists | |
existing_guardrail = await GUARDRAIL_REGISTRY.get_guardrail_by_id_from_db( | |
guardrail_id=guardrail_id, prisma_client=prisma_client | |
) | |
if existing_guardrail is None: | |
raise HTTPException( | |
status_code=404, detail=f"Guardrail with ID {guardrail_id} not found" | |
) | |
result = await GUARDRAIL_REGISTRY.update_guardrail_in_db( | |
guardrail_id=guardrail_id, | |
guardrail=request.guardrail, | |
prisma_client=prisma_client, | |
) | |
return result | |
except HTTPException as e: | |
raise e | |
except Exception as e: | |
raise HTTPException(status_code=500, detail=str(e)) | |
async def delete_guardrail(guardrail_id: str): | |
""" | |
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" | |
} | |
``` | |
""" | |
from litellm.proxy.guardrails.guardrail_registry import IN_MEMORY_GUARDRAIL_HANDLER | |
from litellm.proxy.proxy_server import prisma_client | |
if prisma_client is None: | |
raise HTTPException(status_code=500, detail="Prisma client not initialized") | |
try: | |
# Check if guardrail exists | |
existing_guardrail = await GUARDRAIL_REGISTRY.get_guardrail_by_id_from_db( | |
guardrail_id=guardrail_id, prisma_client=prisma_client | |
) | |
if existing_guardrail is None: | |
raise HTTPException( | |
status_code=404, detail=f"Guardrail with ID {guardrail_id} not found" | |
) | |
result = await GUARDRAIL_REGISTRY.delete_guardrail_from_db( | |
guardrail_id=guardrail_id, prisma_client=prisma_client | |
) | |
# delete in memory guardrail | |
IN_MEMORY_GUARDRAIL_HANDLER.delete_in_memory_guardrail( | |
guardrail_id=guardrail_id, | |
) | |
return result | |
except HTTPException as e: | |
raise e | |
except Exception as e: | |
raise HTTPException(status_code=500, detail=str(e)) | |
async def patch_guardrail(guardrail_id: str, request: PatchGuardrailRequest): | |
""" | |
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" | |
} | |
``` | |
""" | |
from litellm.proxy.guardrails.guardrail_registry import IN_MEMORY_GUARDRAIL_HANDLER | |
from litellm.proxy.proxy_server import prisma_client | |
if prisma_client is None: | |
raise HTTPException(status_code=500, detail="Prisma client not initialized") | |
try: | |
# Check if guardrail exists and get current data | |
existing_guardrail = await GUARDRAIL_REGISTRY.get_guardrail_by_id_from_db( | |
guardrail_id=guardrail_id, prisma_client=prisma_client | |
) | |
if existing_guardrail is None: | |
raise HTTPException( | |
status_code=404, detail=f"Guardrail with ID {guardrail_id} not found" | |
) | |
# Create updated guardrail object | |
guardrail_name = ( | |
request.guardrail_name | |
if request.guardrail_name is not None | |
else existing_guardrail.get("guardrail_name") | |
) | |
# Update litellm_params if default_on is provided or pii_entities_config is provided | |
litellm_params = LitellmParams( | |
**dict(existing_guardrail.get("litellm_params", {})) | |
) | |
if ( | |
request.litellm_params is not None | |
and request.litellm_params.default_on is not None | |
): | |
litellm_params.default_on = request.litellm_params.default_on | |
if ( | |
request.litellm_params is not None | |
and request.litellm_params.pii_entities_config is not None | |
): | |
litellm_params.pii_entities_config = ( | |
request.litellm_params.pii_entities_config | |
) | |
# Update guardrail_info if provided | |
guardrail_info = ( | |
request.guardrail_info | |
if request.guardrail_info is not None | |
else existing_guardrail.get("guardrail_info", {}) | |
) | |
# Create the guardrail object | |
guardrail = Guardrail( | |
guardrail_name=guardrail_name or "", | |
litellm_params=litellm_params, | |
guardrail_info=guardrail_info, | |
) | |
result = await GUARDRAIL_REGISTRY.update_guardrail_in_db( | |
guardrail_id=guardrail_id, | |
guardrail=guardrail, | |
prisma_client=prisma_client, | |
) | |
# update in memory guardrail | |
IN_MEMORY_GUARDRAIL_HANDLER.update_in_memory_guardrail( | |
guardrail_id=guardrail_id, | |
guardrail=guardrail, | |
) | |
return result | |
except HTTPException as e: | |
raise e | |
except Exception as e: | |
verbose_proxy_logger.exception(f"Error updating guardrail: {e}") | |
raise HTTPException(status_code=500, detail=str(e)) | |
async def get_guardrail_info(guardrail_id: str): | |
""" | |
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" | |
} | |
``` | |
""" | |
from litellm.proxy.guardrails.guardrail_registry import IN_MEMORY_GUARDRAIL_HANDLER | |
from litellm.proxy.proxy_server import prisma_client | |
if prisma_client is None: | |
raise HTTPException(status_code=500, detail="Prisma client not initialized") | |
try: | |
result = await GUARDRAIL_REGISTRY.get_guardrail_by_id_from_db( | |
guardrail_id=guardrail_id, prisma_client=prisma_client | |
) | |
if result is None: | |
result = IN_MEMORY_GUARDRAIL_HANDLER.get_guardrail_by_id( | |
guardrail_id=guardrail_id | |
) | |
if result is None: | |
raise HTTPException( | |
status_code=404, detail=f"Guardrail with ID {guardrail_id} not found" | |
) | |
return GuardrailInfoResponse( | |
guardrail_id=result.get("guardrail_id"), | |
guardrail_name=result.get("guardrail_name"), | |
litellm_params=dict(result.get("litellm_params") or {}), | |
guardrail_info=dict(result.get("guardrail_info") or {}), | |
created_at=result.get("created_at"), | |
updated_at=result.get("updated_at"), | |
) | |
except HTTPException as e: | |
raise e | |
except Exception as e: | |
raise HTTPException(status_code=500, detail=str(e)) | |
async def get_guardrail_ui_settings(): | |
""" | |
Get the UI settings for the guardrails | |
Returns: | |
- Supported entities for guardrails | |
- Supported modes for guardrails | |
- PII entity categories for UI organization | |
""" | |
# Convert the PII_ENTITY_CATEGORIES_MAP to the format expected by the UI | |
category_maps = [] | |
for category, entities in PII_ENTITY_CATEGORIES_MAP.items(): | |
category_maps.append({"category": category, "entities": entities}) | |
return GuardrailUIAddGuardrailSettings( | |
supported_entities=list(PiiEntityType), | |
supported_actions=list(PiiAction), | |
supported_modes=list(GuardrailEventHooks), | |
pii_entity_categories=category_maps, | |
) | |
def _get_fields_from_model(model_class: Type[BaseModel]) -> List[Dict[str, Any]]: | |
""" | |
Get the fields from a Pydantic model | |
""" | |
fields = [] | |
for field_name, field in model_class.model_fields.items(): | |
# Get field metadata | |
description = field.description or field_name | |
# Check if this field is in the required_fields class variable | |
required = field.is_required() | |
field_type: Optional[GuardrailParamUITypes] = None | |
field_json_schema_extra = getattr(field, "json_schema_extra", {}) | |
if field_json_schema_extra and "ui_type" in field_json_schema_extra: | |
field_type = field_json_schema_extra["ui_type"] | |
fields.append( | |
{ | |
"param": field_name, | |
"description": description, | |
"required": required, | |
"type": field_type.value if field_type else None, | |
} | |
) | |
return fields | |
async def get_provider_specific_params(): | |
""" | |
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": [ | |
{ | |
"param": "guardrailIdentifier", | |
"description": "The ID of your guardrail on Bedrock", | |
"required": true | |
}, | |
{ | |
"param": "guardrailVersion", | |
"description": "The version of your Bedrock guardrail (e.g., DRAFT or version number)", | |
"required": true | |
} | |
], | |
"presidio": [ | |
{ | |
"param": "presidio_analyzer_api_base", | |
"description": "Base URL for the Presidio analyzer API", | |
"required": true | |
}, | |
{ | |
"param": "presidio_anonymizer_api_base", | |
"description": "Base URL for the Presidio anonymizer API", | |
"required": true | |
}, | |
{ | |
"param": "output_parse_pii", | |
"description": "Whether to parse PII in model outputs", | |
"required": false, | |
"type": "bool" | |
} | |
] | |
} | |
``` | |
""" | |
# Get fields from the models | |
bedrock_fields = _get_fields_from_model(BedrockGuardrailConfigModel) | |
presidio_fields = _get_fields_from_model(PresidioPresidioConfigModelUserInterface) | |
lakera_v2_fields = _get_fields_from_model(LakeraV2GuardrailConfigModel) | |
# Return the provider-specific parameters | |
provider_params = { | |
SupportedGuardrailIntegrations.BEDROCK.value: bedrock_fields, | |
SupportedGuardrailIntegrations.PRESIDIO.value: presidio_fields, | |
SupportedGuardrailIntegrations.LAKERA_V2.value: lakera_v2_fields, | |
} | |
return provider_params | |