From ae24bfe8cb48ffc9db5f09d30e4c6a0f90bfa426 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Tue, 17 Feb 2026 16:56:42 -0800 Subject: [PATCH] fix description --- .../litellm_content_filter/content_filter.py | 48 ++++++++++++++++++- .../eu_ai_act_article5_fr.yaml | 2 +- 2 files changed, 48 insertions(+), 2 deletions(-) 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 4ae3f6b35f..c4ade2f1a8 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 @@ -264,6 +264,52 @@ class ContentFilterGuardrail(CustomGuardrail): f"{len(self.category_keywords)} keywords" ) + @staticmethod + def _resolve_category_file_path(file_path: str) -> str: + """ + Resolve a category file path that may be relative. + + Paths in policy templates (e.g. category_file) are often stored as + relative paths like "litellm/proxy/.../policy_templates/file.yaml". + These only work when the CWD is the project root. In production + (Docker, installed packages, etc.) the CWD is different, so the + file isn't found. + + Resolution order: + 1. Return as-is if absolute or already exists. + 2. Try joining the full path relative to this module's directory. + 3. Progressively strip leading path components and try each suffix + relative to this module's directory (handles paths like + "litellm/proxy/.../policy_templates/file.yaml" by finding the + "policy_templates/file.yaml" suffix that exists). + + Args: + file_path: The file path to resolve (absolute or relative). + + Returns: + The resolved absolute-ish path, or the original path if + resolution fails (caller should check existence). + """ + if os.path.isabs(file_path) or os.path.exists(file_path): + return file_path + + module_dir = os.path.dirname(__file__) + + # Try the full relative path joined to the module directory + candidate = os.path.join(module_dir, file_path) + if os.path.exists(candidate): + return candidate + + # Progressively strip leading components to find a matching suffix + parts = file_path.split("/") + for i in range(1, len(parts)): + suffix = os.path.join(*parts[i:]) + candidate = os.path.join(module_dir, suffix) + if os.path.exists(candidate): + return candidate + + return file_path + def _load_categories(self, categories: List[ContentFilterCategoryConfig]) -> None: """ Load content categories from configuration. @@ -302,7 +348,7 @@ class ContentFilterGuardrail(CustomGuardrail): # Load category file (custom or default) if custom_file: - category_file_path = custom_file + category_file_path = self._resolve_category_file_path(custom_file) else: # Try .yaml first, then .json (e.g. harm_toxic_abuse.json) yaml_path = os.path.join(categories_dir, f"{category_name}.yaml") diff --git a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/policy_templates/eu_ai_act_article5_fr.yaml b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/policy_templates/eu_ai_act_article5_fr.yaml index 7c7c8aab4b..88f07d1e57 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/policy_templates/eu_ai_act_article5_fr.yaml +++ b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/policy_templates/eu_ai_act_article5_fr.yaml @@ -2,7 +2,7 @@ # Utilise une logique conditionnelle : BLOQUER si un mot identificateur + un mot de blocage apparaissent ensemble # Référence : https://artificialintelligenceact.eu/article/5/ category_name: "eu_ai_act_article5_prohibited_practices_fr" -description: "Détecte les pratiques interdites de l'Article 5 de la loi sur l'IA de l'UE (français)" +description: "Detects EU AI Act Article 5 prohibited practices using conditional keyword matching in French" default_action: "BLOCK" # MOTS IDENTIFICATEURS - Actions qui pourraient créer des systèmes interdits