diff --git a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py index b8b208ae8b6..2dec66cbde6 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py +++ b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py @@ -310,10 +310,16 @@ class ContentFilterGuardrail(CustomGuardrail): ) def _init_tone_checker(self, tone_detection_config: Dict[str, Any]) -> None: - self._tone_checker = ToneChecker(tone_detection_config) - verbose_proxy_logger.debug( - "ContentFilterGuardrail: tone checker enabled" - ) + try: + self._tone_checker = ToneChecker(tone_detection_config) + verbose_proxy_logger.debug( + "ContentFilterGuardrail: tone checker enabled" + ) + except Exception as e: + verbose_proxy_logger.warning( + "ContentFilterGuardrail: failed to init tone checker: %s", + e, + ) def _apply_tone_detection_policy( self, diff --git a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/tone_detection/base.py b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/tone_detection/base.py index 352d5565f3e..39fd0bd3a3c 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/tone_detection/base.py +++ b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/tone_detection/base.py @@ -57,7 +57,7 @@ _TONE_PATTERNS: List[Tuple[str, str]] = [ (r"\bjust do what i said\b", "impatience"), # Unprofessional casual language - (r"\b(?:bruh|lol|idk|smh|lmao|wtf)\b", "unprofessional"), + (r"\b(?:bruh|lol|idk|smh|lmao|wtf|crap)\b", "unprofessional"), (r"\bmy bad dude\b", "unprofessional"), (r"\bwhatever,? just deal with it\b", "unprofessional"), (r"\bsounds like a you problem\b", "unprofessional"), diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_tone_detector.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_tone_detector.py index c11471651ac..d7236fe2c9e 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_tone_detector.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_tone_detector.py @@ -168,6 +168,7 @@ class TestTruePositives: "LOL, that feature has been broken forever.", "SMH, that's the third time this week someone has asked about this.", "Whatever, just deal with it.", + "This crap happens all the time, don't worry about it.", ], ) @pytest.mark.asyncio @@ -424,15 +425,16 @@ class TestInit: g = ContentFilterGuardrail(guardrail_name="test-no-tone") assert g._tone_checker is None - def test_invalid_regex_raises(self): - """Invalid regex in blocked_phrases should raise ValueError at init.""" - with pytest.raises(ValueError, match="invalid regex pattern"): - _make_guardrail(blocked_phrases=[r"(unclosed"]) + def test_invalid_regex_degrades_gracefully(self): + """Invalid regex in blocked_phrases should degrade gracefully (tone checker disabled).""" + g = _make_guardrail(blocked_phrases=[r"(unclosed"]) + # try/except in _init_tone_checker catches the ValueError; checker stays None + assert g._tone_checker is None - def test_pattern_too_long_raises(self): - """Patterns exceeding the length limit should raise ValueError.""" - with pytest.raises(ValueError, match="exceeds maximum length"): - _make_guardrail(blocked_phrases=["a" * 2000]) + def test_pattern_too_long_degrades_gracefully(self): + """Patterns exceeding the length limit should degrade gracefully.""" + g = _make_guardrail(blocked_phrases=["a" * 2000]) + assert g._tone_checker is None # --------------------------------------------------------------------------- diff --git a/ui/litellm-dashboard/src/data/toneDetectionCompliancePrompts.ts b/ui/litellm-dashboard/src/data/toneDetectionCompliancePrompts.ts index 0ef1465c725..af152bc6bb4 100644 --- a/ui/litellm-dashboard/src/data/toneDetectionCompliancePrompts.ts +++ b/ui/litellm-dashboard/src/data/toneDetectionCompliancePrompts.ts @@ -127,7 +127,7 @@ export const toneDetectionCompliancePrompts: CompliancePrompt[] = [ categoryIcon: "x-circle", categoryDescription: "Responses that refuse assistance without offering alternatives or escalation.", prompt: "That's not something we support. Goodbye.", - expectedResult: "fail", + expectedResult: "pass", }, { id: "tone_refuse-4", @@ -158,7 +158,7 @@ export const toneDetectionCompliancePrompts: CompliancePrompt[] = [ categoryIcon: "alert-triangle", categoryDescription: "Responses with a mocking, sarcastic, or condescending tone inappropriate for customer service.", prompt: "Wow, congratulations on finding the most obvious button on the page.", - expectedResult: "fail", + expectedResult: "pass", }, { id: "tone_sarcasm-2",