diff --git a/litellm/integrations/custom_guardrail.py b/litellm/integrations/custom_guardrail.py
index b52f1b3095..60f812fc73 100644
--- a/litellm/integrations/custom_guardrail.py
+++ b/litellm/integrations/custom_guardrail.py
@@ -11,9 +11,7 @@ from litellm.types.guardrails import (
Mode,
PiiEntityType,
)
-from litellm.types.llms.openai import (
- AllMessageValues,
-)
+from litellm.types.llms.openai import AllMessageValues
from litellm.types.proxy.guardrails.guardrail_hooks.base import GuardrailConfigModel
from litellm.types.utils import (
CallTypes,
@@ -136,6 +134,17 @@ class CustomGuardrail(CustomLogger):
f"Event hook {event_hook} is not in the supported event hooks {supported_event_hooks}"
)
+ def get_disable_global_guardrail(self, data: dict) -> Optional[bool]:
+ """
+ Returns True if the global guardrail should be disabled
+ """
+ if "disable_global_guardrail" in data:
+ return data["disable_global_guardrail"]
+ metadata = data.get("litellm_metadata") or data.get("metadata", {})
+ if "disable_global_guardrail" in metadata:
+ return metadata["disable_global_guardrail"]
+ return False
+
def get_guardrail_from_metadata(
self, data: dict
) -> Union[List[str], List[Dict[str, DynamicGuardrailParams]]]:
@@ -252,6 +261,7 @@ class CustomGuardrail(CustomLogger):
Returns True if the guardrail should be run on the event_type
"""
requested_guardrails = self.get_guardrail_from_metadata(data)
+ disable_global_guardrail = self.get_disable_global_guardrail(data)
verbose_logger.debug(
"inside should_run_guardrail for guardrail=%s event_type= %s guardrail_supported_event_hooks= %s requested_guardrails= %s self.default_on= %s",
self.guardrail_name,
@@ -260,7 +270,7 @@ class CustomGuardrail(CustomLogger):
requested_guardrails,
self.default_on,
)
- if self.default_on is True:
+ if self.default_on is True and disable_global_guardrail is not True:
if self._event_hook_is_event_type(event_type):
if isinstance(self.event_hook, Mode):
try:
diff --git a/litellm/proxy/_experimental/out/api-reference.html b/litellm/proxy/_experimental/out/api-reference/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/api-reference.html
rename to litellm/proxy/_experimental/out/api-reference/index.html
diff --git a/litellm/proxy/_experimental/out/guardrails.html b/litellm/proxy/_experimental/out/guardrails.html
deleted file mode 100644
index fb03d0380c..0000000000
--- a/litellm/proxy/_experimental/out/guardrails.html
+++ /dev/null
@@ -1 +0,0 @@
-
LiteLLM Dashboard
\ No newline at end of file
diff --git a/litellm/proxy/_experimental/out/logs.html b/litellm/proxy/_experimental/out/logs/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/logs.html
rename to litellm/proxy/_experimental/out/logs/index.html
diff --git a/litellm/proxy/_experimental/out/model-hub.html b/litellm/proxy/_experimental/out/model-hub/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/model-hub.html
rename to litellm/proxy/_experimental/out/model-hub/index.html
diff --git a/litellm/proxy/_experimental/out/model_hub_table.html b/litellm/proxy/_experimental/out/model_hub_table/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/model_hub_table.html
rename to litellm/proxy/_experimental/out/model_hub_table/index.html
diff --git a/litellm/proxy/_experimental/out/models-and-endpoints.html b/litellm/proxy/_experimental/out/models-and-endpoints/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/models-and-endpoints.html
rename to litellm/proxy/_experimental/out/models-and-endpoints/index.html
diff --git a/litellm/proxy/_experimental/out/onboarding.html b/litellm/proxy/_experimental/out/onboarding.html
deleted file mode 100644
index 49527b37db..0000000000
--- a/litellm/proxy/_experimental/out/onboarding.html
+++ /dev/null
@@ -1 +0,0 @@
-LiteLLM Dashboard
\ No newline at end of file
diff --git a/litellm/proxy/_experimental/out/organizations.html b/litellm/proxy/_experimental/out/organizations/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/organizations.html
rename to litellm/proxy/_experimental/out/organizations/index.html
diff --git a/litellm/proxy/_experimental/out/playground.html b/litellm/proxy/_experimental/out/playground/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/playground.html
rename to litellm/proxy/_experimental/out/playground/index.html
diff --git a/litellm/proxy/_experimental/out/teams.html b/litellm/proxy/_experimental/out/teams/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/teams.html
rename to litellm/proxy/_experimental/out/teams/index.html
diff --git a/litellm/proxy/_experimental/out/test-key.html b/litellm/proxy/_experimental/out/test-key/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/test-key.html
rename to litellm/proxy/_experimental/out/test-key/index.html
diff --git a/litellm/proxy/_experimental/out/usage.html b/litellm/proxy/_experimental/out/usage/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/usage.html
rename to litellm/proxy/_experimental/out/usage/index.html
diff --git a/litellm/proxy/_experimental/out/users.html b/litellm/proxy/_experimental/out/users/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/users.html
rename to litellm/proxy/_experimental/out/users/index.html
diff --git a/litellm/proxy/_experimental/out/virtual-keys.html b/litellm/proxy/_experimental/out/virtual-keys/index.html
similarity index 100%
rename from litellm/proxy/_experimental/out/virtual-keys.html
rename to litellm/proxy/_experimental/out/virtual-keys/index.html
diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py
index d6b2d664f9..2abd7a3003 100644
--- a/litellm/proxy/_types.py
+++ b/litellm/proxy/_types.py
@@ -812,6 +812,7 @@ class KeyRequestBase(GenerateRequestBase):
key: Optional[str] = None
budget_id: Optional[str] = None
tags: Optional[List[str]] = None
+ disable_global_guardrails: Optional[bool] = None
enforced_params: Optional[List[str]] = None
allowed_routes: Optional[list] = []
allowed_passthrough_routes: Optional[list] = None
@@ -1357,6 +1358,7 @@ class NewTeamRequest(TeamBase):
prompts: Optional[List[str]] = None
object_permission: Optional[LiteLLM_ObjectPermissionBase] = None
allowed_passthrough_routes: Optional[list] = None
+ disable_global_guardrails: Optional[bool] = None
model_rpm_limit: Optional[Dict[str, int]] = None
rpm_limit_type: Optional[
Literal["guaranteed_throughput", "best_effort_throughput"]
@@ -1418,6 +1420,7 @@ class UpdateTeamRequest(LiteLLMPydanticObjectBase):
model_aliases: Optional[dict] = None
guardrails: Optional[List[str]] = None
object_permission: Optional[LiteLLM_ObjectPermissionBase] = None
+ disable_global_guardrails: Optional[bool] = None
team_member_budget: Optional[float] = None
team_member_rpm_limit: Optional[int] = None
team_member_tpm_limit: Optional[int] = None
@@ -3257,6 +3260,7 @@ LiteLLM_ManagementEndpoint_MetadataFields = [
]
LiteLLM_ManagementEndpoint_MetadataFields_Premium = [
+ "disable_global_guardrails",
"guardrails",
"tags",
"team_member_key_duration",
diff --git a/litellm/proxy/litellm_pre_call_utils.py b/litellm/proxy/litellm_pre_call_utils.py
index 89c16ce824..0a7fc62a42 100644
--- a/litellm/proxy/litellm_pre_call_utils.py
+++ b/litellm/proxy/litellm_pre_call_utils.py
@@ -585,7 +585,6 @@ class LiteLLMProxyRequestSetup:
if user_api_key_dict.budget_reset_at
else None
),
-
user_api_key_auth_metadata=user_api_key_dict.metadata,
)
return user_api_key_logged_metadata
@@ -668,6 +667,12 @@ class LiteLLMProxyRequestSetup:
tags_to_add=key_metadata["tags"],
)
)
+ if "disable_global_guardrails" in key_metadata and isinstance(
+ key_metadata["disable_global_guardrails"], bool
+ ):
+ data[_metadata_variable_name]["disable_global_guardrails"] = key_metadata[
+ "disable_global_guardrails"
+ ]
if "spend_logs_metadata" in key_metadata and isinstance(
key_metadata["spend_logs_metadata"], dict
):
@@ -936,6 +941,12 @@ async def add_litellm_data_to_request( # noqa: PLR0915
request_tags=data[_metadata_variable_name].get("tags"),
tags_to_add=team_metadata["tags"],
)
+ if "disable_global_guardrails" in team_metadata and isinstance(
+ team_metadata["disable_global_guardrails"], bool
+ ):
+ data[_metadata_variable_name]["disable_global_guardrails"] = team_metadata[
+ "disable_global_guardrails"
+ ]
if "spend_logs_metadata" in team_metadata and isinstance(
team_metadata["spend_logs_metadata"], dict
):
@@ -1240,7 +1251,7 @@ def _add_guardrails_from_key_or_team_metadata(
) -> None:
"""
Helper add guardrails from key or team metadata to request data
-
+
Key guardrails are set first, then team guardrails are appended (without duplicates).
Args:
@@ -1254,19 +1265,25 @@ def _add_guardrails_from_key_or_team_metadata(
# Initialize guardrails set (avoiding duplicates)
combined_guardrails = set()
-
+
# Add key-level guardrails first
if key_metadata and "guardrails" in key_metadata:
- if isinstance(key_metadata["guardrails"], list) and len(key_metadata["guardrails"]) > 0:
+ if (
+ isinstance(key_metadata["guardrails"], list)
+ and len(key_metadata["guardrails"]) > 0
+ ):
_premium_user_check()
combined_guardrails.update(key_metadata["guardrails"])
-
+
# Add team-level guardrails (set automatically handles duplicates)
if team_metadata and "guardrails" in team_metadata:
- if isinstance(team_metadata["guardrails"], list) and len(team_metadata["guardrails"]) > 0:
+ if (
+ isinstance(team_metadata["guardrails"], list)
+ and len(team_metadata["guardrails"]) > 0
+ ):
_premium_user_check()
combined_guardrails.update(team_metadata["guardrails"])
-
+
# Set combined guardrails in metadata as list
if combined_guardrails:
data[metadata_variable_name]["guardrails"] = list(combined_guardrails)
@@ -1292,23 +1309,32 @@ def move_guardrails_to_metadata(
)
#########################################################################################
- # User's might send "guardrails" in the request body, we need to add them to the request metadata.
+ # User's might send "guardrails" in the request body, we need to add them to the request metadata.
# Since downstream logic requires "guardrails" to be in the request metadata
#########################################################################################
if "guardrails" in data:
request_body_guardrails = data.pop("guardrails")
- if "guardrails" in data[_metadata_variable_name] and isinstance(data[_metadata_variable_name]["guardrails"], list):
+ if "guardrails" in data[_metadata_variable_name] and isinstance(
+ data[_metadata_variable_name]["guardrails"], list
+ ):
data[_metadata_variable_name]["guardrails"].extend(request_body_guardrails)
else:
data[_metadata_variable_name]["guardrails"] = request_body_guardrails
-
+
#########################################################################################
if "guardrail_config" in data:
request_body_guardrail_config = data.pop("guardrail_config")
- if "guardrail_config" in data[_metadata_variable_name] and isinstance(data[_metadata_variable_name]["guardrail_config"], dict):
- data[_metadata_variable_name]["guardrail_config"].update(request_body_guardrail_config)
+ if "guardrail_config" in data[_metadata_variable_name] and isinstance(
+ data[_metadata_variable_name]["guardrail_config"], dict
+ ):
+ data[_metadata_variable_name]["guardrail_config"].update(
+ request_body_guardrail_config
+ )
else:
- data[_metadata_variable_name]["guardrail_config"] = request_body_guardrail_config
+ data[_metadata_variable_name][
+ "guardrail_config"
+ ] = request_body_guardrail_config
+
def add_provider_specific_headers_to_request(
data: dict,
diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py
index f9257ffe07..fdbea56598 100644
--- a/litellm/proxy/management_endpoints/team_endpoints.py
+++ b/litellm/proxy/management_endpoints/team_endpoints.py
@@ -688,8 +688,7 @@ async def new_team( # noqa: PLR0915
},
)
-
- if (data.max_budget is not None and user_api_key_dict.user_id is not None):
+ if data.max_budget is not None and user_api_key_dict.user_id is not None:
# Fetch user object to get max_budget
user_obj = await get_user_object(
user_id=user_api_key_dict.user_id,
@@ -699,7 +698,7 @@ async def new_team( # noqa: PLR0915
)
if (
- user_obj is not None
+ user_obj is not None
and user_obj.max_budget is not None
and data.max_budget > user_obj.max_budget
):
diff --git a/tests/test_litellm/integrations/test_custom_guardrail.py b/tests/test_litellm/integrations/test_custom_guardrail.py
index 601c18077a..21206ec948 100644
--- a/tests/test_litellm/integrations/test_custom_guardrail.py
+++ b/tests/test_litellm/integrations/test_custom_guardrail.py
@@ -171,6 +171,79 @@ class TestCustomGuardrailShouldRunGuardrail:
assert result is False
+ def test_should_run_guardrail_with_disable_global_guardrail(self):
+ """Test that disable_global_guardrail disables a global guardrail when set to True"""
+ from litellm.types.guardrails import GuardrailEventHooks
+
+ # Create a guardrail with default_on=True (global guardrail)
+ custom_guardrail = CustomGuardrail(
+ guardrail_name="global_guardrail",
+ default_on=True,
+ event_hook=GuardrailEventHooks.pre_call,
+ )
+
+ # Test 1: Global guardrail runs by default when default_on=True
+ data = {
+ "model": "gpt-3.5-turbo",
+ "messages": [{"role": "user", "content": "test"}],
+ }
+ result = custom_guardrail.should_run_guardrail(
+ data=data, event_type=GuardrailEventHooks.pre_call
+ )
+ assert result is True, "Global guardrail should run when default_on=True"
+
+ # Test 2: Global guardrail is disabled when disable_global_guardrail=True at root level
+ data_with_disable_root = {
+ "model": "gpt-3.5-turbo",
+ "messages": [{"role": "user", "content": "test"}],
+ "disable_global_guardrail": True,
+ }
+ result = custom_guardrail.should_run_guardrail(
+ data=data_with_disable_root, event_type=GuardrailEventHooks.pre_call
+ )
+ assert (
+ result is False
+ ), "Global guardrail should be disabled when disable_global_guardrail=True"
+
+ # Test 3: Global guardrail is disabled when disable_global_guardrail=True in litellm_metadata
+ data_with_disable_litellm = {
+ "model": "gpt-3.5-turbo",
+ "messages": [{"role": "user", "content": "test"}],
+ "litellm_metadata": {"disable_global_guardrail": True},
+ }
+ result = custom_guardrail.should_run_guardrail(
+ data=data_with_disable_litellm, event_type=GuardrailEventHooks.pre_call
+ )
+ assert (
+ result is False
+ ), "Global guardrail should be disabled when disable_global_guardrail=True in litellm_metadata"
+
+ # Test 4: Global guardrail is disabled when disable_global_guardrail=True in metadata
+ data_with_disable_metadata = {
+ "model": "gpt-3.5-turbo",
+ "messages": [{"role": "user", "content": "test"}],
+ "metadata": {"disable_global_guardrail": True},
+ }
+ result = custom_guardrail.should_run_guardrail(
+ data=data_with_disable_metadata, event_type=GuardrailEventHooks.pre_call
+ )
+ assert (
+ result is False
+ ), "Global guardrail should be disabled when disable_global_guardrail=True in metadata"
+
+ # Test 5: Global guardrail runs when disable_global_guardrail=False
+ data_with_disable_false = {
+ "model": "gpt-3.5-turbo",
+ "messages": [{"role": "user", "content": "test"}],
+ "disable_global_guardrail": False,
+ }
+ result = custom_guardrail.should_run_guardrail(
+ data=data_with_disable_false, event_type=GuardrailEventHooks.pre_call
+ )
+ assert (
+ result is True
+ ), "Global guardrail should still run when disable_global_guardrail=False"
+
class TestApplyGuardrailCheck:
def test_apply_guardrail_check_only_on_direct_implementation(self):
@@ -304,7 +377,9 @@ class TestGuardrailLoggingAggregation:
self._invoke_add_log(request_data)
- info = request_data["litellm_metadata"]["standard_logging_guardrail_information"]
+ info = request_data["litellm_metadata"][
+ "standard_logging_guardrail_information"
+ ]
assert isinstance(info, list)
assert len(info) == 2
assert info[1]["guardrail_name"] == "test_guardrail"
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/teams/components/modals/CreateTeamModal.tsx b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/modals/CreateTeamModal.tsx
index 34fb8fbb6e..80d99b5a9e 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/teams/components/modals/CreateTeamModal.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/modals/CreateTeamModal.tsx
@@ -1,4 +1,4 @@
-import { Button as Button2, Form, Input, Modal, Select as Select2, Tooltip } from "antd";
+import { Button as Button2, Form, Input, Modal, Select as Select2, Switch, Tooltip } from "antd";
import { Accordion, AccordionBody, AccordionHeader, Text, TextInput } from "@tremor/react";
import { InfoCircleOutlined } from "@ant-design/icons";
import {
@@ -452,6 +452,25 @@ const CreateTeamModal = ({
}))}
/>
+
+ Disable Global Guardrails{" "}
+
+
+
+
+ }
+ name="disable_global_guardrails"
+ className="mt-4"
+ valuePropName="checked"
+ help="Bypass global guardrails for this team"
+ >
+
+
diff --git a/ui/litellm-dashboard/src/components/OldTeams.tsx b/ui/litellm-dashboard/src/components/OldTeams.tsx
index 325df0ac7b..638d2bf173 100644
--- a/ui/litellm-dashboard/src/components/OldTeams.tsx
+++ b/ui/litellm-dashboard/src/components/OldTeams.tsx
@@ -30,7 +30,7 @@ import {
Text,
TextInput,
} from "@tremor/react";
-import { Button as Button2, Form, Input, Modal, Select as Select2, Tooltip, Typography } from "antd";
+import { Button as Button2, Form, Input, Modal, Select as Select2, Switch, Tooltip, Typography } from "antd";
import React, { useEffect, useState } from "react";
import { formatNumberWithCommas } from "../utils/dataUtils";
import { fetchTeams } from "./common_components/fetch_teams";
@@ -1262,6 +1262,26 @@ const Teams: React.FC = ({
}))}
/>
+
+ Disable Global Guardrails{" "}
+
+
+
+
+ }
+ name="disable_global_guardrails"
+ className="mt-4"
+ valuePropName="checked"
+ help="Bypass global guardrails for this team"
+ >
+
+
diff --git a/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx b/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx
index 02837eb666..1cb4623ca6 100644
--- a/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx
+++ b/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx
@@ -3,7 +3,7 @@ import React, { useState, useEffect, useCallback } from "react";
import { Button, TextInput, Grid, Col } from "@tremor/react";
import { Text, Title, Accordion, AccordionHeader, AccordionBody } from "@tremor/react";
import { CopyToClipboard } from "react-copy-to-clipboard";
-import { Button as Button2, Modal, Form, Input, Select, Radio } from "antd";
+import { Button as Button2, Modal, Form, Input, Select, Radio, Switch } from "antd";
import NumericalInput from "../shared/numerical_input";
import { getModelDisplayName } from "../key_team_helpers/fetch_available_models_team_key";
import SchemaFormFields from "../common_components/check_openapi_schema";
@@ -879,6 +879,37 @@ const CreateKey: React.FC = ({
options={guardrailsList.map((name) => ({ value: name, label: name }))}
/>
+
+ Disable Global Guardrails{" "}
+
+ e.stopPropagation()} // Prevent accordion from collapsing when clicking link
+ >
+
+
+
+
+ }
+ name="disable_global_guardrails"
+ className="mt-4"
+ valuePropName="checked"
+ help={
+ premiumUser
+ ? "Bypass global guardrails for this key"
+ : "Premium feature - Upgrade to disable global guardrails by key"
+ }
+ >
+
+
diff --git a/ui/litellm-dashboard/src/components/team/team_info.tsx b/ui/litellm-dashboard/src/components/team/team_info.tsx
index 0e3c5e92e6..3e7f12e751 100644
--- a/ui/litellm-dashboard/src/components/team/team_info.tsx
+++ b/ui/litellm-dashboard/src/components/team/team_info.tsx
@@ -25,7 +25,7 @@ import {
teamUpdateCall,
getGuardrailsList,
} from "@/components/networking";
-import { Button, Form, Input, Select, message, Modal, Tooltip } from "antd";
+import { Button, Form, Input, Select, Switch, message, Modal, Tooltip } from "antd";
import { InfoCircleOutlined } from "@ant-design/icons";
import { ArrowLeftIcon } from "@heroicons/react/outline";
import MemberModal from "./edit_membership";
@@ -558,6 +558,7 @@ const TeamInfoView: React.FC = ({
team_member_tpm_limit: info.team_member_budget_table?.tpm_limit,
team_member_rpm_limit: info.team_member_budget_table?.rpm_limit,
guardrails: info.metadata?.guardrails || [],
+ disable_global_guardrails: info.metadata?.disable_global_guardrails || false,
metadata: info.metadata
? JSON.stringify((({ logging, ...rest }) => rest)(info.metadata), null, 2)
: "",
@@ -673,6 +674,25 @@ const TeamInfoView: React.FC = ({
/>
+
+ Disable Global Guardrails{" "}
+
+
+
+
+ }
+ name="disable_global_guardrails"
+ valuePropName="checked"
+ help="Bypass global guardrails for this team"
+ >
+
+
+
form.setFieldValue("vector_stores", values)}
@@ -806,6 +826,17 @@ const TeamInfoView: React.FC = ({
{info.blocked ? "Blocked" : "Active"}
+
+
Disable Global Guardrails
+
+ {info.metadata?.disable_global_guardrails === true ? (
+ Enabled - Global guardrails bypassed
+ ) : (
+ Disabled - Global guardrails active
+ )}
+
+
+
+
+ Disable Global Guardrails{" "}
+
+
+
+
+ }
+ name="disable_global_guardrails"
+ valuePropName="checked"
+ >
+
+
+