fix(guardrails): allow native lifecycle logging-only scope

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-09-29 08:25:44 +00:00
parent c63fd3bd29
commit 76c02ea7e9
3 changed files with 29 additions and 2 deletions

View file

@ -809,7 +809,6 @@ class CustomGuardrail(CustomLogger):
def supports_logging_only_scope(self) -> bool:
return (
self.uses_apply_guardrail_interface()
and not self.use_native_lifecycle_hooks
and type(self).async_logging_hook is CustomGuardrail.async_logging_hook
)

View file

@ -1,5 +1,5 @@
from collections.abc import Iterable
from typing import Final
from typing import ClassVar, Final
from unittest.mock import AsyncMock, MagicMock
import pytest
@ -956,6 +956,10 @@ class _LoggingOnlyScopeUnsupportedGuardrail(_LoggingOnlyScopeSupportedGuardrail)
return kwargs, result
class _LoggingOnlyScopeNativeGuardrail(_LoggingOnlyScopeSupportedGuardrail):
use_native_lifecycle_hooks: ClassVar[bool] = True
class TestLoggingOnlyScopeValidation:
def _initialize(
self,
@ -968,9 +972,13 @@ class TestLoggingOnlyScopeValidation:
guardrail_type: Final = "logging_only_scope_test"
def _initializer(litellm_params: LitellmParams, guardrail: Guardrail) -> CustomGuardrail:
supported_event_hooks: Final = (
[GuardrailEventHooks.logging_only] if callback_type.use_native_lifecycle_hooks else None
)
return callback_type(
guardrail_name=guardrail["guardrail_name"],
event_hook=litellm_params.mode,
supported_event_hooks=supported_event_hooks,
)
registry_module.guardrail_initializer_registry[guardrail_type] = _initializer
@ -1041,6 +1049,15 @@ class TestLoggingOnlyScopeValidation:
assert callback.logging_only_scope == "both"
def test_output_scope_accepted_for_native_lifecycle_guardrail(self) -> None:
callback: Final = self._initialize(
mode="logging_only",
scope="output",
callback_type=_LoggingOnlyScopeNativeGuardrail,
)
assert callback.logging_only_scope == "output"
def test_invalid_scope_fails_litellm_params_validation(self) -> None:
with pytest.raises(ValidationError):
LitellmParams(guardrail="test", mode="logging_only", logging_only_scope="request")

View file

@ -2961,6 +2961,17 @@ class _NativeLifecycleLoggingGuardrail(CustomGuardrail):
return inputs
@pytest.mark.asyncio
async def test_native_lifecycle_guardrail_logging_only_scope_scans_only_input():
guardrail: Final = _NativeLifecycleLoggingGuardrail()
guardrail.logging_only_scope = "input"
kwargs, response = _logged_call([{"role": "user", "content": "native lifecycle input"}])
await guardrail.async_logging_hook(kwargs, response, CallTypes.acompletion.value)
assert guardrail.calls == [("request", ["native lifecycle input"])]
@pytest.mark.asyncio
async def test_native_lifecycle_guardrail_logging_only_scans_assembled_response():
"""A use_native_lifecycle_hooks guardrail accepts mode logging_only and its