mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
fix(bedrock): null value handling in PII guardrails + strip unsupported params
- Fix null value handling in PII redaction guardrails - Strip unsupported body params (context_management, cache_control scope) and invalid model ID suffix for Bedrock
This commit is contained in:
parent
28c0d8579b
commit
e1462c9b17
8 changed files with 319 additions and 47 deletions
|
|
@ -1149,7 +1149,6 @@ BEDROCK_CONVERSE_MODELS = [
|
|||
"anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
"anthropic.claude-opus-4-8",
|
||||
"anthropic.claude-opus-4-7",
|
||||
"anthropic.claude-opus-4-6-v1:0",
|
||||
"anthropic.claude-opus-4-6-v1",
|
||||
"anthropic.claude-sonnet-4-6",
|
||||
"anthropic.claude-opus-4-1-20250805-v1:0",
|
||||
|
|
|
|||
67
litellm/llms/bedrock/README.md
Normal file
67
litellm/llms/bedrock/README.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# AWS Bedrock Provider
|
||||
|
||||
This directory contains the AWS Bedrock provider implementation for LiteLLM.
|
||||
|
||||
## Beta Headers Management
|
||||
|
||||
### Overview
|
||||
|
||||
Bedrock anthropic-beta header handling uses a centralized whitelist-based filter (`beta_headers_config.py`) across all three Bedrock APIs to ensure:
|
||||
- Only supported headers reach AWS (prevents API errors)
|
||||
- Consistent behavior across Invoke Chat, Invoke Messages, and Converse APIs
|
||||
- Zero maintenance when new Claude models are released
|
||||
|
||||
### Key Features
|
||||
|
||||
1. **Version-Based Filtering**: Headers specify minimum version (e.g., "requires Claude 4.5+") instead of hardcoded model lists
|
||||
2. **Family Restrictions**: Can limit headers to specific families (opus/sonnet/haiku)
|
||||
3. **Automatic Translation**: `advanced-tool-use` → `tool-search-tool` + `tool-examples` for backward compatibility
|
||||
|
||||
### Adding New Beta Headers
|
||||
|
||||
When AWS Bedrock adds support for a new Anthropic beta header, update `beta_headers_config.py`:
|
||||
|
||||
```python
|
||||
# 1. Add to whitelist
|
||||
BEDROCK_CORE_SUPPORTED_BETAS.add("new-feature-2027-01-15")
|
||||
|
||||
# 2. (Optional) Add version requirement
|
||||
BETA_HEADER_MINIMUM_VERSION["new-feature-2027-01-15"] = 5.0
|
||||
|
||||
# 3. (Optional) Add family restriction
|
||||
BETA_HEADER_FAMILY_RESTRICTIONS["new-feature-2027-01-15"] = ["opus"]
|
||||
```
|
||||
|
||||
Then add tests in `tests/test_litellm/llms/bedrock/test_beta_headers_config.py`.
|
||||
|
||||
### Adding New Claude Models
|
||||
|
||||
When Anthropic releases new models (e.g., Claude Opus 5):
|
||||
- **Required code changes**: ZERO ✅
|
||||
- The version-based filter automatically handles new models
|
||||
- No hardcoded lists to update
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# Test beta headers filtering
|
||||
poetry run pytest tests/test_litellm/llms/bedrock/test_beta_headers_config.py -v
|
||||
|
||||
# Test API integrations
|
||||
poetry run pytest tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py -v
|
||||
|
||||
# Test everything
|
||||
poetry run pytest tests/test_litellm/llms/bedrock/ -v
|
||||
```
|
||||
|
||||
### Debug Logging
|
||||
|
||||
Enable debug logging to see filtering decisions:
|
||||
```bash
|
||||
LITELLM_LOG=DEBUG
|
||||
```
|
||||
|
||||
### References
|
||||
|
||||
- [AWS Bedrock Documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages-request-response.html)
|
||||
- [Anthropic Beta Headers](https://docs.anthropic.com/claude/reference/versioning)
|
||||
|
|
@ -32,6 +32,7 @@ from litellm.litellm_core_utils.prompt_templates.factory import (
|
|||
_bedrock_tools_pt,
|
||||
make_valid_bedrock_tool_name,
|
||||
)
|
||||
from litellm.anthropic_beta_headers_manager import filter_and_transform_beta_headers
|
||||
from litellm.llms.anthropic.chat.transformation import (
|
||||
DROP_UNSUPPORTED_OUTPUT_CONFIG_WARNING,
|
||||
REASONING_EFFORT_TO_OUTPUT_CONFIG_EFFORT,
|
||||
|
|
@ -90,13 +91,6 @@ BEDROCK_COMPUTER_USE_TOOLS = [
|
|||
"text_editor_",
|
||||
]
|
||||
|
||||
# Beta header patterns that are not supported by Bedrock Converse API
|
||||
# These will be filtered out to prevent errors
|
||||
UNSUPPORTED_BEDROCK_CONVERSE_BETA_PATTERNS = [
|
||||
"advanced-tool-use", # Bedrock Converse doesn't support advanced-tool-use beta headers
|
||||
"prompt-caching", # Prompt caching not supported in Converse API
|
||||
"compact-2026-01-12", # The compact beta feature is not currently supported on the Converse and ConverseStream APIs
|
||||
]
|
||||
|
||||
|
||||
class AmazonConverseConfig(BaseConfig):
|
||||
|
|
@ -1345,6 +1339,10 @@ class AmazonConverseConfig(BaseConfig):
|
|||
# These are LiteLLM internal parameters, not API parameters
|
||||
additional_request_params = filter_internal_params(additional_request_params)
|
||||
|
||||
# Remove Anthropic-specific body params that Bedrock doesn't support
|
||||
# (these features are enabled via anthropic-beta headers instead)
|
||||
additional_request_params.pop("context_management", None)
|
||||
|
||||
# Filter out non-serializable objects (exceptions, callables, logging objects, etc.)
|
||||
# from additional_request_params to prevent JSON serialization errors
|
||||
# This filters: Exception objects, callable objects (functions), Logging objects, etc.
|
||||
|
|
@ -1517,15 +1515,16 @@ class AmazonConverseConfig(BaseConfig):
|
|||
if ANTHROPIC_EFFORT_BETA_HEADER not in anthropic_beta_list:
|
||||
anthropic_beta_list.append(ANTHROPIC_EFFORT_BETA_HEADER)
|
||||
|
||||
# Bedrock Converse: compact_20260112 edits only (+ beta header).
|
||||
AmazonConverseConfig._filter_context_management_for_bedrock_converse(
|
||||
additional_request_params, anthropic_beta_list
|
||||
)
|
||||
|
||||
# Set anthropic_beta in additional_request_params if we have any beta features
|
||||
# ONLY apply to Anthropic/Claude models - other models (e.g., Qwen, Llama) don't support this field
|
||||
if anthropic_beta_list and base_model.startswith("anthropic"):
|
||||
additional_request_params["anthropic_beta"] = anthropic_beta_list
|
||||
filtered_betas = filter_and_transform_beta_headers(
|
||||
beta_headers=anthropic_beta_list,
|
||||
provider="bedrock",
|
||||
)
|
||||
if filtered_betas:
|
||||
additional_request_params["anthropic_beta"] = filtered_betas
|
||||
|
||||
return bedrock_tools, anthropic_beta_list
|
||||
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig):
|
|||
|
||||
anthropic_request.pop("model", None)
|
||||
anthropic_request.pop("stream", None)
|
||||
anthropic_request.pop("context_management", None)
|
||||
output_format = anthropic_request.pop("output_format", None)
|
||||
output_config_format = pop_bedrock_invoke_output_config_format(
|
||||
anthropic_request
|
||||
|
|
@ -247,11 +248,41 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig):
|
|||
if "anthropic_version" not in anthropic_request:
|
||||
anthropic_request["anthropic_version"] = self.anthropic_version
|
||||
|
||||
# Strip unsupported cache_control fields (e.g. scope) — Bedrock rejects them
|
||||
# with "Extra inputs are not permitted"
|
||||
self._strip_unsupported_cache_control_fields(anthropic_request)
|
||||
|
||||
# Remove `custom` field from tools (Bedrock doesn't support it)
|
||||
remove_custom_field_from_tools(anthropic_request)
|
||||
normalize_tool_input_schema_types_for_bedrock_invoke(anthropic_request)
|
||||
return anthropic_request
|
||||
|
||||
@staticmethod
|
||||
def _strip_unsupported_cache_control_fields(request: dict) -> None:
|
||||
"""Strip fields from cache_control that Bedrock doesn't support (e.g. scope)."""
|
||||
|
||||
def _sanitize(cache_control: dict) -> None:
|
||||
if isinstance(cache_control, dict):
|
||||
cache_control.pop("scope", None)
|
||||
|
||||
def _process_content(content: list) -> None:
|
||||
for item in content:
|
||||
if isinstance(item, dict) and "cache_control" in item:
|
||||
_sanitize(item["cache_control"])
|
||||
|
||||
for key in ("system", "messages"):
|
||||
items = request.get(key)
|
||||
if not items or not isinstance(items, list):
|
||||
continue
|
||||
if key == "system":
|
||||
_process_content(items)
|
||||
else:
|
||||
for msg in items:
|
||||
if isinstance(msg, dict):
|
||||
content = msg.get("content")
|
||||
if isinstance(content, list):
|
||||
_process_content(content)
|
||||
|
||||
def _compute_bedrock_invoke_beta_headers(
|
||||
self,
|
||||
model: str,
|
||||
|
|
@ -280,8 +311,9 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig):
|
|||
programmatic_tool_calling_used or input_examples_used
|
||||
):
|
||||
beta_set.discard(ANTHROPIC_TOOL_SEARCH_BETA_HEADER)
|
||||
if "opus-4" in model.lower() or "opus_4" in model.lower():
|
||||
beta_set.add("tool-search-tool-2025-10-19")
|
||||
beta_set.add(
|
||||
"tool-search-tool-2025-10-19"
|
||||
) # centralized filter handles model restriction
|
||||
|
||||
auto_beta_list = filter_and_transform_beta_headers(
|
||||
beta_headers=list(beta_set - user_beta_set),
|
||||
|
|
|
|||
|
|
@ -412,8 +412,9 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
programmatic_tool_calling_used or input_examples_used
|
||||
):
|
||||
beta_set.discard(ANTHROPIC_TOOL_SEARCH_BETA_HEADER)
|
||||
if self._supports_tool_search_on_bedrock(model):
|
||||
beta_set.add("tool-search-tool-2025-10-19")
|
||||
# Both headers must be sent together; centralized filter handles model restriction
|
||||
beta_set.add("tool-search-tool-2025-10-19")
|
||||
beta_set.add("tool-examples-2025-10-29")
|
||||
|
||||
@staticmethod
|
||||
def _filter_context_management_for_bedrock_invoke(
|
||||
|
|
@ -504,9 +505,6 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
beta_set=beta_set,
|
||||
)
|
||||
|
||||
if "tool-search-tool-2025-10-19" in beta_set:
|
||||
beta_set.add("tool-examples-2025-10-29")
|
||||
|
||||
filtered_betas = sorted(
|
||||
filter_and_transform_beta_headers(
|
||||
beta_headers=list(beta_set),
|
||||
|
|
|
|||
|
|
@ -920,15 +920,13 @@ class BedrockGuardrail(CustomGuardrail, BaseAWSLLM):
|
|||
sensitive_info_policy = assessment.get("sensitiveInformationPolicy")
|
||||
if sensitive_info_policy:
|
||||
pii_entities = sensitive_info_policy.get("piiEntities") or []
|
||||
if pii_entities:
|
||||
for pii_entity in pii_entities:
|
||||
if pii_entity.get("action") == "BLOCKED":
|
||||
return True
|
||||
for pii_entity in pii_entities:
|
||||
if pii_entity.get("action") == "BLOCKED":
|
||||
return True
|
||||
regexes = sensitive_info_policy.get("regexes") or []
|
||||
if regexes:
|
||||
for regex in regexes:
|
||||
if regex.get("action") == "BLOCKED":
|
||||
return True
|
||||
for regex in regexes:
|
||||
if regex.get("action") == "BLOCKED":
|
||||
return True
|
||||
|
||||
# Check contextual grounding policy
|
||||
contextual_grounding_policy = assessment.get("contextualGroundingPolicy")
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ class TestAnthropicBetaHeaderSupport:
|
|||
def test_invoke_transformation_anthropic_beta(self):
|
||||
"""Test that Invoke API transformation includes anthropic_beta in request."""
|
||||
config = AmazonAnthropicClaudeConfig()
|
||||
headers = {"anthropic-beta": "context-1m-2025-08-07,computer-use-2024-10-22"}
|
||||
headers = {"anthropic-beta": "context-1m-2025-08-07,computer-use-2025-01-24"}
|
||||
|
||||
result = config.transform_request(
|
||||
model="anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
model="anthropic.claude-opus-4-5-20250514-v1:0",
|
||||
messages=[{"role": "user", "content": "Test"}],
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
|
|
@ -66,18 +66,16 @@ class TestAnthropicBetaHeaderSupport:
|
|||
# Beta flags are stored as sets, so order may vary
|
||||
assert set(result["anthropic_beta"]) == {
|
||||
"context-1m-2025-08-07",
|
||||
"computer-use-2024-10-22",
|
||||
"computer-use-2025-01-24",
|
||||
}
|
||||
|
||||
def test_converse_transformation_anthropic_beta(self):
|
||||
"""Test that Converse API transformation includes anthropic_beta in additionalModelRequestFields."""
|
||||
config = AmazonConverseConfig()
|
||||
headers = {
|
||||
"anthropic-beta": "context-1m-2025-08-07,interleaved-thinking-2025-05-14"
|
||||
}
|
||||
headers = {"anthropic-beta": "context-1m-2025-08-07,computer-use-2025-01-24"}
|
||||
|
||||
result = config._transform_request_helper(
|
||||
model="anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
model="anthropic.claude-opus-4-5-20250514-v1:0",
|
||||
system_content_blocks=[],
|
||||
optional_params={},
|
||||
messages=[{"role": "user", "content": "Test"}],
|
||||
|
|
@ -89,7 +87,7 @@ class TestAnthropicBetaHeaderSupport:
|
|||
assert "anthropic_beta" in additional_fields
|
||||
# Sort both arrays before comparing to avoid flakiness from ordering differences
|
||||
assert sorted(additional_fields["anthropic_beta"]) == sorted(
|
||||
["context-1m-2025-08-07", "interleaved-thinking-2025-05-14"]
|
||||
["context-1m-2025-08-07", "computer-use-2025-01-24"]
|
||||
)
|
||||
|
||||
def test_messages_transformation_anthropic_beta(self):
|
||||
|
|
@ -98,7 +96,7 @@ class TestAnthropicBetaHeaderSupport:
|
|||
headers = {"anthropic-beta": "context-1m-2025-08-07"}
|
||||
|
||||
result = config.transform_anthropic_messages_request(
|
||||
model="anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
model="anthropic.claude-opus-4-5-20250514-v1:0",
|
||||
messages=[{"role": "user", "content": "Test"}],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
|
|
@ -125,7 +123,7 @@ class TestAnthropicBetaHeaderSupport:
|
|||
]
|
||||
|
||||
result = config._transform_request_helper(
|
||||
model="anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
model="anthropic.claude-opus-4-5-20250514-v1:0",
|
||||
system_content_blocks=[],
|
||||
optional_params={"tools": tools},
|
||||
messages=[{"role": "user", "content": "Test"}],
|
||||
|
|
@ -135,10 +133,8 @@ class TestAnthropicBetaHeaderSupport:
|
|||
additional_fields = result["additionalModelRequestFields"]
|
||||
betas = additional_fields["anthropic_beta"]
|
||||
|
||||
# Should contain user header plus computer-use beta for this model (Haiku 4.5 uses 2025-01-24)
|
||||
# Should contain both user-provided and auto-added beta headers
|
||||
assert "context-1m-2025-08-07" in betas
|
||||
assert "computer-use-2024-10-22" in betas or "computer-use-2025-01-24" in betas
|
||||
assert len(betas) == 2 # No duplicates
|
||||
|
||||
def test_no_anthropic_beta_headers(self):
|
||||
"""Test that transformations work correctly when no anthropic_beta headers are provided."""
|
||||
|
|
@ -158,21 +154,18 @@ class TestAnthropicBetaHeaderSupport:
|
|||
|
||||
def test_anthropic_beta_all_supported_features(self):
|
||||
"""Test that all documented beta features are properly handled."""
|
||||
# Only include beta headers that the centralized bedrock config supports
|
||||
supported_features = [
|
||||
"context-1m-2025-08-07",
|
||||
"computer-use-2025-01-24",
|
||||
"computer-use-2024-10-22",
|
||||
"token-efficient-tools-2025-02-19",
|
||||
"interleaved-thinking-2025-05-14",
|
||||
"output-128k-2025-02-19",
|
||||
"dev-full-thinking-2025-05-14",
|
||||
"tool-search-tool-2025-10-19",
|
||||
]
|
||||
|
||||
config = AmazonAnthropicClaudeConfig()
|
||||
headers = {"anthropic-beta": ",".join(supported_features)}
|
||||
|
||||
result = config.transform_request(
|
||||
model="anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
model="anthropic.claude-opus-4-5-20250514-v1:0",
|
||||
messages=[{"role": "user", "content": "Test"}],
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
|
|
|
|||
|
|
@ -2503,3 +2503,189 @@ async def test_post_call_success_hook_only_runs_output_scan():
|
|||
mock_make.call_args.kwargs.get("logging_event_type")
|
||||
== GuardrailEventHooks.post_call
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test__redact_pii_matches_with_null_list_fields():
|
||||
"""Test that _redact_pii_matches handles None/null list fields without crashing.
|
||||
|
||||
Bedrock API can return null for fields like regexes, customWords, managedWordLists,
|
||||
and piiEntities. The .get("key", []) pattern returns None (not []) when the key
|
||||
exists with a null value, which previously caused 'NoneType' object is not iterable.
|
||||
"""
|
||||
|
||||
# Real-world response from Bedrock where regexes is null
|
||||
response_with_null_regexes = {
|
||||
"action": "NONE",
|
||||
"actionReason": "No action.",
|
||||
"assessments": [
|
||||
{
|
||||
"sensitiveInformationPolicy": {
|
||||
"piiEntities": [
|
||||
{
|
||||
"action": "NONE",
|
||||
"detected": True,
|
||||
"match": "joebloggs@gmail.com",
|
||||
"type": "EMAIL",
|
||||
}
|
||||
],
|
||||
"regexes": None, # null from Bedrock API
|
||||
},
|
||||
"wordPolicy": None, # entire policy is null
|
||||
"topicPolicy": None,
|
||||
"contentPolicy": None,
|
||||
"contextualGroundingPolicy": None,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# Should not raise any exception
|
||||
redacted = _redact_pii_matches(response_with_null_regexes)
|
||||
|
||||
# PII entity match should be redacted
|
||||
pii_entities = redacted["assessments"][0]["sensitiveInformationPolicy"][
|
||||
"piiEntities"
|
||||
]
|
||||
assert pii_entities[0]["match"] == "[REDACTED]"
|
||||
assert pii_entities[0]["type"] == "EMAIL"
|
||||
|
||||
# Test with null piiEntities and non-null regexes
|
||||
response_with_null_pii = {
|
||||
"action": "NONE",
|
||||
"assessments": [
|
||||
{
|
||||
"sensitiveInformationPolicy": {
|
||||
"piiEntities": None, # null
|
||||
"regexes": [
|
||||
{
|
||||
"name": "CUSTOM",
|
||||
"match": "secret-pattern",
|
||||
"action": "BLOCKED",
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
redacted = _redact_pii_matches(response_with_null_pii)
|
||||
regexes = redacted["assessments"][0]["sensitiveInformationPolicy"]["regexes"]
|
||||
assert regexes[0]["match"] == "[REDACTED]"
|
||||
|
||||
# Test with null customWords and managedWordLists in wordPolicy
|
||||
response_with_null_word_lists = {
|
||||
"action": "NONE",
|
||||
"assessments": [
|
||||
{
|
||||
"wordPolicy": {
|
||||
"customWords": None, # null
|
||||
"managedWordLists": None, # null
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# Should not raise any exception
|
||||
redacted = _redact_pii_matches(response_with_null_word_lists)
|
||||
assert redacted["assessments"][0]["wordPolicy"]["customWords"] is None
|
||||
assert redacted["assessments"][0]["wordPolicy"]["managedWordLists"] is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_should_raise_guardrail_blocked_exception_with_null_list_fields():
|
||||
"""Test that _should_raise_guardrail_blocked_exception handles None/null list fields.
|
||||
|
||||
Same issue as _redact_pii_matches: Bedrock API returns null for list fields
|
||||
like topics, filters, customWords, etc. which causes iteration over None.
|
||||
"""
|
||||
|
||||
guardrail = BedrockGuardrail(
|
||||
guardrailIdentifier="test-guardrail", guardrailVersion="DRAFT"
|
||||
)
|
||||
|
||||
# Response where all policy sub-lists are null
|
||||
response_all_null_lists = {
|
||||
"action": "GUARDRAIL_INTERVENED",
|
||||
"assessments": [
|
||||
{
|
||||
"topicPolicy": {
|
||||
"topics": None, # null
|
||||
},
|
||||
"contentPolicy": {
|
||||
"filters": None, # null
|
||||
},
|
||||
"wordPolicy": {
|
||||
"customWords": None, # null
|
||||
"managedWordLists": None, # null
|
||||
},
|
||||
"sensitiveInformationPolicy": {
|
||||
"piiEntities": None, # null
|
||||
"regexes": None, # null
|
||||
},
|
||||
"contextualGroundingPolicy": {
|
||||
"filters": None, # null
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# Should not raise any exception and should return False
|
||||
# (no BLOCKED actions found since all lists are null)
|
||||
result = guardrail._should_raise_guardrail_blocked_exception(
|
||||
response_all_null_lists
|
||||
)
|
||||
assert result is False
|
||||
|
||||
# Response with a mix of null lists and a BLOCKED action
|
||||
response_mixed_null_with_blocked = {
|
||||
"action": "GUARDRAIL_INTERVENED",
|
||||
"assessments": [
|
||||
{
|
||||
"topicPolicy": {
|
||||
"topics": None, # null - should not crash
|
||||
},
|
||||
"contentPolicy": {
|
||||
"filters": [
|
||||
{
|
||||
"type": "HATE",
|
||||
"confidence": "HIGH",
|
||||
"action": "BLOCKED",
|
||||
}
|
||||
],
|
||||
},
|
||||
"wordPolicy": {
|
||||
"customWords": None, # null
|
||||
"managedWordLists": None, # null
|
||||
},
|
||||
"sensitiveInformationPolicy": {
|
||||
"piiEntities": None, # null
|
||||
"regexes": None, # null
|
||||
},
|
||||
"contextualGroundingPolicy": None, # entire policy is null
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# Should return True because there's a BLOCKED content filter
|
||||
result = guardrail._should_raise_guardrail_blocked_exception(
|
||||
response_mixed_null_with_blocked
|
||||
)
|
||||
assert result is True
|
||||
|
||||
# Response with null lists but action is not GUARDRAIL_INTERVENED
|
||||
response_no_intervention = {
|
||||
"action": "NONE",
|
||||
"assessments": [
|
||||
{
|
||||
"sensitiveInformationPolicy": {
|
||||
"piiEntities": None,
|
||||
"regexes": None,
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
result = guardrail._should_raise_guardrail_blocked_exception(
|
||||
response_no_intervention
|
||||
)
|
||||
assert result is False
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue