mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix: real stub class in the missing-package fallback
Runtime regression in the previous simplification — the guardrail registry iterates every registered class at load time and calls get_supported_event_hooks(). Fallback of ConductGuardrail = None crashed the whole registry with AttributeError, which cascaded into unrelated guardrails' tests (noma_v2, repelloai, hide_secrets, provider_specific_params, etc.). Fallback now defines ConductGuardrail as a real subclass of CustomGuardrail with the required class attrs (SUPPORTED_EVENT_HOOKS + get_supported_event_hooks). Matches the pattern the guardrails_ai integration already uses in the same repo. raise_if_missing_package still fires before instantiation so users see the friendly pip install error. All four budget gates re-verified locally against upstream/litellm_internal_staging: ruff_strict_gate OK test_quality_gate OK type_discipline_gate OK type_check_gate OK
This commit is contained in:
parent
46eac90614
commit
a62337a9ea
1 changed files with 35 additions and 14 deletions
|
|
@ -1,11 +1,18 @@
|
|||
"""Conduct Guard as a LiteLLM guardrail.
|
||||
|
||||
Pure alias for the ``conduct-litellm-guard`` PyPI package. The
|
||||
Thin alias for the ``conduct-litellm-guard`` PyPI package. The
|
||||
``ConductGuard`` class ships with ``SUPPORTED_EVENT_HOOKS`` +
|
||||
``get_supported_event_hooks`` since plugin 0.2.3, so this file no
|
||||
longer needs a subclass wrapper — keeps LiteLLM's type-discipline /
|
||||
basedpyright / test-quality budget gates satisfied.
|
||||
|
||||
When the standalone package isn't installed we still register a real
|
||||
stub class so LiteLLM's guardrail registry can scan
|
||||
``get_supported_event_hooks`` at load time without crashing (see
|
||||
BerriAI/litellm#38143 CI regression: registry iteration expects every
|
||||
registered class to expose the hooks classmethod). Instantiation of
|
||||
the stub raises ``ImportError`` via ``raise_if_missing_package``.
|
||||
|
||||
Install: ``pip install "conduct-litellm-guard>=0.2.3"``
|
||||
Source: https://github.com/sseshachala/conductai/tree/main/packages/conduct-litellm-guard
|
||||
Docs: https://conductai.ai/guard
|
||||
|
|
@ -13,21 +20,16 @@ Docs: https://conductai.ai/guard
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import ClassVar
|
||||
|
||||
from litellm.integrations.custom_guardrail import CustomGuardrail
|
||||
|
||||
_import_error_message = (
|
||||
"conduct-litellm-guard is required for the Conduct guardrail. "
|
||||
'Install it with: pip install "conduct-litellm-guard>=0.2.3"'
|
||||
)
|
||||
|
||||
|
||||
# ── Base plugin import ─────────────────────────────────────────────────
|
||||
# Raising ImportError at module load caused the guardrail-hook auto-loader
|
||||
# to treat a missing ``conduct-litellm-guard`` as "hook unavailable" and
|
||||
# silently drop the registration. Users saw configs load with no guardrail
|
||||
# active and no error message. Instead we surface the friendly error at
|
||||
# config-load time from :func:`raise_if_missing_package` — called by
|
||||
# ``initialize_guardrail`` before construction.
|
||||
# (cursor[bot] finding on BerriAI/litellm#38143.)
|
||||
|
||||
try:
|
||||
from conduct_litellm_guard import ConductGuard as ConductGuardrail
|
||||
from conduct_litellm_guard.guardrail import (
|
||||
|
|
@ -36,18 +38,37 @@ try:
|
|||
from conduct_litellm_guard.guardrail import GuardDecision
|
||||
|
||||
_import_error: ImportError | None = None
|
||||
except ImportError as _import_err:
|
||||
ConductGuardrail = None
|
||||
except ImportError as _err:
|
||||
|
||||
class ConductGuardrail(CustomGuardrail):
|
||||
"""Stub used when ``conduct-litellm-guard`` isn't installed.
|
||||
|
||||
Exposes the class-level surface LiteLLM's guardrail registry
|
||||
scans at load time — ``SUPPORTED_EVENT_HOOKS`` +
|
||||
``get_supported_event_hooks`` — so the registry doesn't crash
|
||||
when this hook is discovered without the runtime dependency.
|
||||
``initialize_guardrail`` calls ``raise_if_missing_package``
|
||||
before ever constructing this class, so users see a friendly
|
||||
``pip install`` error rather than the stub silently activating.
|
||||
"""
|
||||
|
||||
SUPPORTED_EVENT_HOOKS: ClassVar[tuple[str, ...]] = ("pre_call",)
|
||||
|
||||
@classmethod
|
||||
def get_supported_event_hooks(cls) -> list[str]:
|
||||
return list(cls.SUPPORTED_EVENT_HOOKS)
|
||||
|
||||
ConductGuardrailBlocked = None
|
||||
GuardDecision = None
|
||||
_import_error = _import_err
|
||||
_import_error = _err
|
||||
|
||||
|
||||
def raise_if_missing_package() -> None:
|
||||
"""Called by ``initialize_guardrail`` before constructing the class.
|
||||
|
||||
Surfaces the friendly ``pip install`` error at the actionable moment
|
||||
(config load) rather than silently dropping the hook at module load.
|
||||
(config load) rather than silently dropping the hook or letting the
|
||||
stub run.
|
||||
"""
|
||||
if _import_error is not None:
|
||||
raise ImportError(_import_error_message) from _import_error
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue