mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-19 04:54:37 +00:00
fix:errors due to change in field names
This commit is contained in:
parent
bb0e661d11
commit
556a2d8dba
4 changed files with 99 additions and 50 deletions
|
|
@ -21,10 +21,12 @@ def initialize_guardrail(
|
|||
import litellm
|
||||
|
||||
_cb = SingulrGuardrail(
|
||||
api_base=litellm_params.api_base,
|
||||
api_key=litellm_params.api_key,
|
||||
enforcement_entity_id=getattr(litellm_params, "enforcement_entity_id", None),
|
||||
guardrail_id=getattr(litellm_params, "guardrail_id", None),
|
||||
singulr_api_base=getattr(litellm_params, "singulr_api_base", None)
|
||||
or litellm_params.api_base,
|
||||
singulr_api_key=getattr(litellm_params, "singulr_api_key", None)
|
||||
or litellm_params.api_key,
|
||||
singulr_application_id=getattr(litellm_params, "singulr_application_id", None),
|
||||
singulr_guardrail_id=getattr(litellm_params, "singulr_guardrail_id", None),
|
||||
block_on_error=getattr(litellm_params, "block_on_error", None),
|
||||
guardrail_name=guardrail.get(
|
||||
"guardrail_name",
|
||||
|
|
|
|||
|
|
@ -39,18 +39,20 @@ _GUARD_ENDPOINT = "/api/v1/ai-gateway/litellm"
|
|||
class SingulrGuardrail(CustomGuardrail):
|
||||
def __init__(
|
||||
self,
|
||||
api_key: Optional[str] = None,
|
||||
api_base: Optional[str] = None,
|
||||
enforcement_entity_id: Optional[str] = None,
|
||||
guardrail_id: Optional[str] = None,
|
||||
singulr_api_key: Optional[str] = None,
|
||||
singulr_api_base: Optional[str] = None,
|
||||
singulr_application_id: Optional[str] = None,
|
||||
singulr_guardrail_id: Optional[str] = None,
|
||||
block_on_error: Optional[bool] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
self.api_key = api_key or os.environ.get("SINGULR_API_KEY")
|
||||
self.singulr_api_key = singulr_api_key or os.environ.get("SINGULR_API_KEY")
|
||||
|
||||
self.api_base = (api_base or os.environ.get("SINGULR_API_BASE") or _DEFAULT_API_BASE).rstrip("/")
|
||||
self.singulr_api_base = (
|
||||
singulr_api_base or os.environ.get("SINGULR_API_BASE") or _DEFAULT_API_BASE
|
||||
).rstrip("/")
|
||||
|
||||
parsed = urlparse(self.api_base)
|
||||
parsed = urlparse(self.singulr_api_base)
|
||||
if parsed.scheme == "http" and parsed.hostname not in (
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
|
|
@ -59,11 +61,15 @@ class SingulrGuardrail(CustomGuardrail):
|
|||
"Singulr: api_base %s uses plain HTTP. Guardrail payloads contain "
|
||||
"full message content and will be sent unencrypted. Use HTTPS for "
|
||||
"any non-local endpoint.",
|
||||
self.api_base,
|
||||
self.singulr_api_base,
|
||||
)
|
||||
|
||||
self.enforcement_entity_id = enforcement_entity_id or os.environ.get("SINGULR_ENFORCEMENT_ENTITY_ID")
|
||||
self.guardrail_id = guardrail_id or os.environ.get("SINGULR_GUARDRAIL_ID")
|
||||
self.singulr_application_id = singulr_application_id or os.environ.get(
|
||||
"SINGULR_ENFORCEMENT_ENTITY_ID"
|
||||
)
|
||||
self.singulr_guardrail_id = singulr_guardrail_id or os.environ.get(
|
||||
"SINGULR_GUARDRAIL_ID"
|
||||
)
|
||||
|
||||
if block_on_error is None:
|
||||
env = os.environ.get("SINGULR_BLOCK_ON_ERROR", "true")
|
||||
|
|
@ -107,18 +113,18 @@ class SingulrGuardrail(CustomGuardrail):
|
|||
(header, value)
|
||||
for header, value in (
|
||||
("Content-Type", "application/json"),
|
||||
("X-Singulr-Gateway-Token", self.api_key),
|
||||
("X-Singulr-Gateway-Token", self.singulr_api_key),
|
||||
(
|
||||
"X-Singulr-Enforcement-Entity-Id",
|
||||
self.enforcement_entity_id or "",
|
||||
self.singulr_application_id or "",
|
||||
),
|
||||
("X-Singulr-Guardrail-Id", self.guardrail_id or ""),
|
||||
("X-Singulr-Guardrail-Id", self.singulr_guardrail_id or ""),
|
||||
)
|
||||
if value
|
||||
)
|
||||
|
||||
async def _call_api(self, payload: dict[str, Any]) -> Optional[dict[str, Any]]:
|
||||
endpoint = f"{self.api_base}{_GUARD_ENDPOINT}"
|
||||
endpoint = f"{self.singulr_api_base}{_GUARD_ENDPOINT}"
|
||||
verbose_proxy_logger.debug("Singulr: %s", endpoint)
|
||||
|
||||
try:
|
||||
|
|
@ -142,7 +148,9 @@ class SingulrGuardrail(CustomGuardrail):
|
|||
if self.block_on_error:
|
||||
raise GuardrailRaisedException(
|
||||
guardrail_name=self.guardrail_name,
|
||||
message=(f"Singulr API returned HTTP {exc.response.status_code}: {exc.response.text}"),
|
||||
message=(
|
||||
f"Singulr API returned HTTP {exc.response.status_code}: {exc.response.text}"
|
||||
),
|
||||
) from exc
|
||||
return None
|
||||
|
||||
|
|
@ -156,7 +164,9 @@ class SingulrGuardrail(CustomGuardrail):
|
|||
return None
|
||||
|
||||
except ValueError as exc:
|
||||
verbose_proxy_logger.error("Singulr API returned non-JSON response: %s", str(exc))
|
||||
verbose_proxy_logger.error(
|
||||
"Singulr API returned non-JSON response: %s", str(exc)
|
||||
)
|
||||
if self.block_on_error:
|
||||
raise GuardrailRaisedException(
|
||||
guardrail_name=self.guardrail_name,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class SingulrGuardrailConfigModel(GuardrailConfigModel):
|
|||
|
||||
singulr_application_id: Optional[str] = Field(
|
||||
default=None,
|
||||
description="The Singulr application ID. Get application ID Singulr Platform.",
|
||||
description="The Singulr application ID. Get application ID from Singulr Platform.",
|
||||
)
|
||||
|
||||
singulr_guardrail_id: Optional[str] = Field(
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ from litellm.types.proxy.guardrails.guardrail_hooks.singulr import (
|
|||
def singulr_guardrail():
|
||||
"""Create a SingulrGuardrail instance with test credentials."""
|
||||
return SingulrGuardrail(
|
||||
api_base="https://api.test.singulr.ai",
|
||||
api_key="test_token_1234",
|
||||
guardrail_id="test_guardrail_id",
|
||||
enforcement_entity_id="test_enforcement_entity",
|
||||
singulr_api_base="https://api.test.singulr.ai",
|
||||
singulr_api_key="test_token_1234",
|
||||
singulr_guardrail_id="test_guardrail_id",
|
||||
singulr_application_id="test_enforcement_entity",
|
||||
guardrail_name="test-singulr",
|
||||
event_hook="pre_call",
|
||||
default_on=True,
|
||||
|
|
@ -68,26 +68,28 @@ def _make_response(body: dict) -> MagicMock:
|
|||
class TestSingulrConfiguration:
|
||||
def test_init_with_explicit_credentials(self):
|
||||
guardrail = SingulrGuardrail(
|
||||
api_key="test_key",
|
||||
api_base="https://custom.api.local",
|
||||
guardrail_id="id123",
|
||||
enforcement_entity_id="entity123",
|
||||
singulr_api_key="test_key",
|
||||
singulr_api_base="https://custom.api.local",
|
||||
singulr_guardrail_id="id123",
|
||||
singulr_application_id="entity123",
|
||||
guardrail_name="my-guardrail",
|
||||
)
|
||||
assert guardrail.api_key == "test_key"
|
||||
assert guardrail.api_base == "https://custom.api.local"
|
||||
assert guardrail.guardrail_id == "id123"
|
||||
assert guardrail.enforcement_entity_id == "entity123"
|
||||
assert guardrail.singulr_api_key == "test_key"
|
||||
assert guardrail.singulr_api_base == "https://custom.api.local"
|
||||
assert guardrail.singulr_guardrail_id == "id123"
|
||||
assert guardrail.singulr_application_id == "entity123"
|
||||
|
||||
def test_block_on_error_defaults_true(self):
|
||||
guardrail = SingulrGuardrail(api_key="test_key")
|
||||
guardrail = SingulrGuardrail(singulr_api_key="test_key")
|
||||
assert guardrail.block_on_error is True
|
||||
|
||||
def test_http_remote_api_base_logs_warning(self):
|
||||
with patch(
|
||||
"litellm.proxy.guardrails.guardrail_hooks.singulr.singulr.verbose_proxy_logger"
|
||||
) as mock_logger:
|
||||
SingulrGuardrail(api_key="test_key", api_base="http://remote.singulr.ai")
|
||||
SingulrGuardrail(
|
||||
singulr_api_key="test_key", singulr_api_base="http://remote.singulr.ai"
|
||||
)
|
||||
mock_logger.warning.assert_called_once()
|
||||
assert "plain HTTP" in mock_logger.warning.call_args.args[0]
|
||||
|
||||
|
|
@ -95,21 +97,25 @@ class TestSingulrConfiguration:
|
|||
with patch(
|
||||
"litellm.proxy.guardrails.guardrail_hooks.singulr.singulr.verbose_proxy_logger"
|
||||
) as mock_logger:
|
||||
SingulrGuardrail(api_key="test_key", api_base="http://localhost:8000")
|
||||
SingulrGuardrail(
|
||||
singulr_api_key="test_key", singulr_api_base="http://localhost:8000"
|
||||
)
|
||||
mock_logger.warning.assert_not_called()
|
||||
|
||||
def test_https_remote_api_base_no_warning(self):
|
||||
with patch(
|
||||
"litellm.proxy.guardrails.guardrail_hooks.singulr.singulr.verbose_proxy_logger"
|
||||
) as mock_logger:
|
||||
SingulrGuardrail(api_key="test_key", api_base="https://remote.singulr.ai")
|
||||
SingulrGuardrail(
|
||||
singulr_api_key="test_key", singulr_api_base="https://remote.singulr.ai"
|
||||
)
|
||||
mock_logger.warning.assert_not_called()
|
||||
|
||||
def test_only_supports_pre_call_hook(self):
|
||||
"""Singulr only forwards the original request; there is no response
|
||||
text available to scan on the post_call path, so post_call must not
|
||||
be registered as a supported event hook."""
|
||||
guardrail = SingulrGuardrail(api_key="test_key")
|
||||
guardrail = SingulrGuardrail(singulr_api_key="test_key")
|
||||
assert guardrail.supported_event_hooks == [GuardrailEventHooks.pre_call]
|
||||
|
||||
|
||||
|
|
@ -543,8 +549,8 @@ class TestSingulrNonJsonResponse:
|
|||
self, mock_request_data
|
||||
):
|
||||
guardrail = SingulrGuardrail(
|
||||
api_base="https://api.test.singulr.ai",
|
||||
api_key="test_token_1234",
|
||||
singulr_api_base="https://api.test.singulr.ai",
|
||||
singulr_api_key="test_token_1234",
|
||||
guardrail_name="test-singulr",
|
||||
block_on_error=False,
|
||||
)
|
||||
|
|
@ -566,8 +572,8 @@ class TestSingulrNonJsonResponse:
|
|||
self, mock_request_data
|
||||
):
|
||||
guardrail = SingulrGuardrail(
|
||||
api_base="https://api.test.singulr.ai",
|
||||
api_key="test_token_1234",
|
||||
singulr_api_base="https://api.test.singulr.ai",
|
||||
singulr_api_key="test_token_1234",
|
||||
guardrail_name="test-singulr",
|
||||
block_on_error=True,
|
||||
)
|
||||
|
|
@ -595,8 +601,8 @@ class TestSingulrTransportError:
|
|||
self, mock_request_data
|
||||
):
|
||||
guardrail = SingulrGuardrail(
|
||||
api_base="https://api.test.singulr.ai",
|
||||
api_key="test_token_1234",
|
||||
singulr_api_base="https://api.test.singulr.ai",
|
||||
singulr_api_key="test_token_1234",
|
||||
guardrail_name="test-singulr",
|
||||
block_on_error=False,
|
||||
)
|
||||
|
|
@ -618,8 +624,8 @@ class TestSingulrTransportError:
|
|||
self, mock_request_data
|
||||
):
|
||||
guardrail = SingulrGuardrail(
|
||||
api_base="https://api.test.singulr.ai",
|
||||
api_key="test_token_1234",
|
||||
singulr_api_base="https://api.test.singulr.ai",
|
||||
singulr_api_key="test_token_1234",
|
||||
guardrail_name="test-singulr",
|
||||
block_on_error=True,
|
||||
)
|
||||
|
|
@ -647,8 +653,8 @@ class TestSingulrHttpStatusError:
|
|||
self, mock_request_data
|
||||
):
|
||||
guardrail = SingulrGuardrail(
|
||||
api_base="https://api.test.singulr.ai",
|
||||
api_key="test_token_1234",
|
||||
singulr_api_base="https://api.test.singulr.ai",
|
||||
singulr_api_key="test_token_1234",
|
||||
guardrail_name="test-singulr",
|
||||
block_on_error=True,
|
||||
)
|
||||
|
|
@ -676,8 +682,8 @@ class TestSingulrHttpStatusError:
|
|||
self, mock_request_data
|
||||
):
|
||||
guardrail = SingulrGuardrail(
|
||||
api_base="https://api.test.singulr.ai",
|
||||
api_key="test_token_1234",
|
||||
singulr_api_base="https://api.test.singulr.ai",
|
||||
singulr_api_key="test_token_1234",
|
||||
guardrail_name="test-singulr",
|
||||
block_on_error=False,
|
||||
)
|
||||
|
|
@ -709,3 +715,34 @@ class TestSingulrInitializer:
|
|||
)
|
||||
|
||||
assert callable(initialize_guardrail)
|
||||
|
||||
def test_initialize_guardrail_reads_singulr_prefixed_fields(self):
|
||||
"""Regression: the UI config form (and YAML config) populate the
|
||||
singulr_-prefixed fields declared on SingulrGuardrailConfigModel, not
|
||||
the generic api_base/api_key fields. initialize_guardrail must read
|
||||
those, or a UI-configured singulr_api_base is silently ignored and
|
||||
the guardrail falls back to the localhost default."""
|
||||
from litellm.proxy.guardrails.guardrail_hooks.singulr import (
|
||||
initialize_guardrail,
|
||||
)
|
||||
from litellm.types.guardrails import Guardrail, LitellmParams
|
||||
|
||||
litellm_params = LitellmParams(
|
||||
guardrail="singulr",
|
||||
mode="pre_call",
|
||||
singulr_api_base="https://configured.singulr.ai",
|
||||
singulr_api_key="configured_key",
|
||||
singulr_application_id="configured_app_id",
|
||||
singulr_guardrail_id="configured_guardrail_id",
|
||||
)
|
||||
guardrail: Guardrail = {
|
||||
"guardrail_name": "test-singulr",
|
||||
"litellm_params": litellm_params,
|
||||
}
|
||||
|
||||
cb = initialize_guardrail(litellm_params, guardrail)
|
||||
|
||||
assert cb.singulr_api_base == "https://configured.singulr.ai"
|
||||
assert cb.singulr_api_key == "configured_key"
|
||||
assert cb.singulr_application_id == "configured_app_id"
|
||||
assert cb.singulr_guardrail_id == "configured_guardrail_id"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue