fix: SUPPORTED_EVENT_HOOKS must be GuardrailEventHooks enum, not str

LiteLLM's guardrail registry scans SUPPORTED_EVENT_HOOKS and calls
.value on each entry to build the mode allowlist. Plugin 0.2.3 shipped
bare strings, which raised AttributeError on three upstream tests
(same three as the pre-0.2.3 None-registration failure).

- Fallback stub now uses GuardrailEventHooks.pre_call.
- Docstring and pip install message updated to >=0.2.4.
- Test asserts against the enum member (which is what LiteLLM's
  registry scan actually sees).

Requires plugin conduct-litellm-guard >=0.2.4 (already tagged and
publishing).

All four budget gates verified locally green:
  ruff_strict, test_quality, type_discipline, type_check
This commit is contained in:
Conduct AI 2026-09-10 22:29:09 -05:00
parent 2fe6a2ad24
commit e054c6c785
No known key found for this signature in database
2 changed files with 12 additions and 8 deletions

View file

@ -2,7 +2,7 @@
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
``get_supported_event_hooks`` since plugin 0.2.4, so this file no
longer needs a subclass wrapper keeps LiteLLM's type-discipline /
basedpyright / test-quality budget gates satisfied.
@ -13,7 +13,7 @@ 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"``
Install: ``pip install "conduct-litellm-guard>=0.2.4"``
Source: https://github.com/sseshachala/conductai/tree/main/packages/conduct-litellm-guard
Docs: https://conductai.ai/guard
"""
@ -23,10 +23,11 @@ from __future__ import annotations
from typing import ClassVar
from litellm.integrations.custom_guardrail import CustomGuardrail
from litellm.types.guardrails import GuardrailEventHooks
_import_error_message = (
"conduct-litellm-guard is required for the Conduct guardrail. "
'Install it with: pip install "conduct-litellm-guard>=0.2.3"'
'Install it with: pip install "conduct-litellm-guard>=0.2.4"'
)
@ -52,10 +53,10 @@ except ImportError as _err:
``pip install`` error rather than the stub silently activating.
"""
SUPPORTED_EVENT_HOOKS: ClassVar[tuple[str, ...]] = ("pre_call",)
SUPPORTED_EVENT_HOOKS: ClassVar[tuple[GuardrailEventHooks, ...]] = (GuardrailEventHooks.pre_call,)
@classmethod
def get_supported_event_hooks(cls) -> list[str]:
def get_supported_event_hooks(cls) -> list[GuardrailEventHooks]:
return list(cls.SUPPORTED_EVENT_HOOKS) # mutable-ok: LiteLLM registry expects a fresh list
ConductGuardrailBlocked = None

View file

@ -59,13 +59,16 @@ def test_registries_populated() -> None:
def test_only_pre_call_event_hook_advertised() -> None:
"""Regression for veria-ai finding on #38143 —
``during_call`` mode was silently accepted but never evaluated.
Since plugin 0.2.3 the supported-hooks contract lives on
Since plugin 0.2.4 the supported-hooks contract lives on
``ConductGuard`` in the plugin package itself; the LiteLLM shim
is a pure alias, so we verify against the alias."""
is a pure alias, so we verify against the alias. LiteLLM's
registry calls ``.value`` on each entry, so the hooks must be
``GuardrailEventHooks`` enum members, not bare strings."""
from litellm.proxy.guardrails.guardrail_hooks.conduct import ConductGuardrail
from litellm.types.guardrails import GuardrailEventHooks
hooks = ConductGuardrail.get_supported_event_hooks()
assert hooks == ["pre_call"]
assert hooks == [GuardrailEventHooks.pre_call]
def test_initialize_guardrail_returns_wired_callback(