Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions litellm/proxy/guardrails/guardrail_hooks/xecguard/xecguard.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@
httpxSpecialProvider,
)
from litellm.types.guardrails import GuardrailEventHooks
from litellm.types.utils import GenericGuardrailAPIInputs, GuardrailStatus
from litellm.types.utils import (
GenericGuardrailAPIInputs,
GuardrailStatus,
StandardLoggingGuardrailInformation,
)

if TYPE_CHECKING:
from litellm.litellm_core_utils.litellm_logging import (
Expand Down Expand Up @@ -246,16 +250,21 @@ async def async_logging_hook(
"guardrail_intervened" if scan_result.get("decision") == "UNSAFE" else "success"
)
end_time = datetime.now()
kwargs["standard_logging_object"]["guardrail_information"] = {
"duration": (end_time - start_time).total_seconds(),
"end_time": end_time.timestamp(),
"guardrail_mode": "logging_only",
"guardrail_name": "xecguard",
"guardrail_response": scan_result,
"guardrail_status": guardrail_status,
"masked_entity_count": None,
"start_time": start_time.timestamp(),
}
slg = StandardLoggingGuardrailInformation(
guardrail_name=self.guardrail_name or "xecguard",
guardrail_mode=GuardrailEventHooks.logging_only,
guardrail_response=scan_result,
guardrail_status=guardrail_status,
start_time=start_time.timestamp(),
end_time=end_time.timestamp(),
duration=(end_time - start_time).total_seconds(),
masked_entity_count=None,
)
existing = kwargs["standard_logging_object"].get("guardrail_information")
if isinstance(existing, list):
existing.append(slg)
else:
kwargs["standard_logging_object"]["guardrail_information"] = [slg]

except Exception as exc:
verbose_proxy_logger.debug(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1644,12 +1644,37 @@ async def test_async_logging_hook_with_response_records_info(
)
assert out_kwargs is kwargs
assert out_result is result
info = kwargs["standard_logging_object"]["guardrail_information"]
info_list = kwargs["standard_logging_object"]["guardrail_information"]
assert isinstance(info_list, list), "guardrail_information must be a list"
assert len(info_list) == 1
info = info_list[0]
assert info["guardrail_mode"] == "logging_only"
assert info["guardrail_name"] == "xecguard"
assert info["guardrail_name"] == "test-xecguard"
assert info["guardrail_status"] == "success"
assert info["guardrail_response"]["trace_id"] == "lg-1"

@pytest.mark.asyncio
async def test_async_logging_hook_appends_to_existing_guardrail_info(
self, xecguard_guardrail, mock_request_data
):
resp = _make_response({"decision": "SAFE", "trace_id": "lg-4"})
prior_entry = {"guardrail_name": "other-guardrail"}
with patch.object(xecguard_guardrail.async_handler, "post", return_value=resp):
kwargs = {
**mock_request_data,
"standard_logging_object": {"guardrail_information": [prior_entry]},
}
await xecguard_guardrail.async_logging_hook(
kwargs=kwargs,
result=_build_model_response("some answer"),
call_type="acompletion",
)
info_list = kwargs["standard_logging_object"]["guardrail_information"]
assert len(info_list) == 2
assert info_list[0] is prior_entry
assert info_list[1]["guardrail_name"] == "test-xecguard"
assert info_list[1]["guardrail_response"]["trace_id"] == "lg-4"

@pytest.mark.asyncio
async def test_async_logging_hook_without_response_records_info(
self, xecguard_guardrail, mock_request_data
Expand Down Expand Up @@ -1680,7 +1705,9 @@ async def test_async_logging_hook_unsafe_decision_recorded(
result=_build_model_response("x"),
call_type="acompletion",
)
info = kwargs["standard_logging_object"]["guardrail_information"]
info_list = kwargs["standard_logging_object"]["guardrail_information"]
assert isinstance(info_list, list), "guardrail_information must be a list"
info = info_list[0]
assert info["guardrail_status"] == "guardrail_intervened"

@pytest.mark.asyncio
Expand Down
Loading