mirror of
https://github.com/tiennm99/litellm.git
synced 2026-07-10 09:04:10 +00:00
Merge pull request #14640 from Sameerlite/litellm_gardrail_default_latest_message
[Feat]Add last message as default in gaurdrail
This commit is contained in:
@@ -102,6 +102,61 @@ class AmazonConverseConfig(BaseConfig):
|
||||
"performanceConfig": PerformanceConfigBlock,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _convert_consecutive_user_messages_to_guarded_text(
|
||||
messages: List[AllMessageValues], optional_params: dict
|
||||
) -> List[AllMessageValues]:
|
||||
"""
|
||||
Convert consecutive user messages at the end to guarded_text type if guardrailConfig is present
|
||||
and no guarded_text is already present in those messages.
|
||||
"""
|
||||
# Check if guardrailConfig is present
|
||||
if "guardrailConfig" not in optional_params:
|
||||
return messages
|
||||
|
||||
# Find all consecutive user messages at the end
|
||||
consecutive_user_message_indices = []
|
||||
for i in range(len(messages) - 1, -1, -1):
|
||||
if messages[i].get("role") == "user":
|
||||
consecutive_user_message_indices.append(i)
|
||||
else:
|
||||
break
|
||||
|
||||
if not consecutive_user_message_indices:
|
||||
return messages
|
||||
|
||||
# Process each consecutive user message
|
||||
messages_copy = copy.deepcopy(messages)
|
||||
for user_message_index in consecutive_user_message_indices:
|
||||
user_message = messages_copy[user_message_index]
|
||||
content = user_message.get("content", [])
|
||||
|
||||
if isinstance(content, list):
|
||||
has_guarded_text = any(
|
||||
isinstance(item, dict) and item.get("type") == "guarded_text"
|
||||
for item in content
|
||||
)
|
||||
if has_guarded_text:
|
||||
continue # Skip this message if it already has guarded_text
|
||||
|
||||
# Convert text elements to guarded_text
|
||||
new_content = []
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get("type") == "text":
|
||||
new_item = {"type": "guarded_text", "text": item["text"]} # type: ignore
|
||||
new_content.append(new_item)
|
||||
else:
|
||||
new_content.append(item)
|
||||
|
||||
messages_copy[user_message_index]["content"] = new_content # type: ignore
|
||||
elif isinstance(content, str):
|
||||
# If content is a string, convert it to guarded_text
|
||||
messages_copy[user_message_index]["content"] = [ # type: ignore
|
||||
{"type": "guarded_text", "text": content} # type: ignore
|
||||
]
|
||||
|
||||
return messages_copy
|
||||
|
||||
@classmethod
|
||||
def get_config(cls):
|
||||
return {
|
||||
@@ -769,6 +824,11 @@ class AmazonConverseConfig(BaseConfig):
|
||||
headers: Optional[dict] = None,
|
||||
) -> RequestObject:
|
||||
messages, system_content_blocks = self._transform_system_message(messages)
|
||||
|
||||
# Convert last user message to guarded_text if guardrailConfig is present
|
||||
messages = self._convert_consecutive_user_messages_to_guarded_text(
|
||||
messages, optional_params
|
||||
)
|
||||
## TRANSFORMATION ##
|
||||
|
||||
_data: CommonRequestObject = self._transform_request_helper(
|
||||
@@ -821,6 +881,11 @@ class AmazonConverseConfig(BaseConfig):
|
||||
) -> RequestObject:
|
||||
messages, system_content_blocks = self._transform_system_message(messages)
|
||||
|
||||
# Convert last user message to guarded_text if guardrailConfig is present
|
||||
messages = self._convert_consecutive_user_messages_to_guarded_text(
|
||||
messages, optional_params
|
||||
)
|
||||
|
||||
_data: CommonRequestObject = self._transform_request_helper(
|
||||
model=model,
|
||||
system_content_blocks=system_content_blocks,
|
||||
|
||||
@@ -1868,3 +1868,432 @@ def test_guarded_text_guardrail_config_preserved():
|
||||
assert result["inferenceConfig"]["guardrailConfig"]["guardrailIdentifier"] == "gr-abc123"
|
||||
|
||||
|
||||
def test_auto_convert_last_user_message_to_guarded_text():
|
||||
"""Test that last user message is automatically converted to guarded_text when guardrailConfig is present."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "What is the main topic of this legal document?"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {
|
||||
"guardrailConfig": {
|
||||
"guardrailIdentifier": "gr-abc123",
|
||||
"guardrailVersion": "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Test the helper method directly
|
||||
converted_messages = config._convert_consecutive_user_messages_to_guarded_text(messages, optional_params)
|
||||
|
||||
# Verify the conversion
|
||||
assert len(converted_messages) == 1
|
||||
assert converted_messages[0]["role"] == "user"
|
||||
assert len(converted_messages[0]["content"]) == 1
|
||||
assert converted_messages[0]["content"][0]["type"] == "guarded_text"
|
||||
assert converted_messages[0]["content"][0]["text"] == "What is the main topic of this legal document?"
|
||||
|
||||
|
||||
def test_auto_convert_last_user_message_string_content():
|
||||
"""Test that last user message with string content is automatically converted to guarded_text when guardrailConfig is present."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is the main topic of this legal document?"
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {
|
||||
"guardrailConfig": {
|
||||
"guardrailIdentifier": "gr-abc123",
|
||||
"guardrailVersion": "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Test the helper method directly
|
||||
converted_messages = config._convert_consecutive_user_messages_to_guarded_text(messages, optional_params)
|
||||
|
||||
# Verify the conversion
|
||||
assert len(converted_messages) == 1
|
||||
assert converted_messages[0]["role"] == "user"
|
||||
assert len(converted_messages[0]["content"]) == 1
|
||||
assert converted_messages[0]["content"][0]["type"] == "guarded_text"
|
||||
assert converted_messages[0]["content"][0]["text"] == "What is the main topic of this legal document?"
|
||||
|
||||
|
||||
def test_no_conversion_when_no_guardrail_config():
|
||||
"""Test that no conversion happens when guardrailConfig is not present."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "What is the main topic of this legal document?"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {}
|
||||
|
||||
# Test the helper method directly
|
||||
converted_messages = config._convert_consecutive_user_messages_to_guarded_text(messages, optional_params)
|
||||
|
||||
# Verify no conversion happened
|
||||
assert converted_messages == messages
|
||||
|
||||
|
||||
def test_no_conversion_when_guarded_text_already_present():
|
||||
"""Test that no conversion happens when guarded_text is already present in the last user message."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "guarded_text",
|
||||
"text": "This is already guarded"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {
|
||||
"guardrailConfig": {
|
||||
"guardrailIdentifier": "gr-abc123",
|
||||
"guardrailVersion": "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Test the helper method directly
|
||||
converted_messages = config._convert_consecutive_user_messages_to_guarded_text(messages, optional_params)
|
||||
|
||||
# Verify no conversion happened
|
||||
assert converted_messages == messages
|
||||
|
||||
|
||||
def test_auto_convert_with_mixed_content():
|
||||
"""Test that only text elements are converted to guarded_text, other content types are preserved."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "What is the main topic of this legal document?"
|
||||
},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {"url": "https://example.com/image.jpg"}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {
|
||||
"guardrailConfig": {
|
||||
"guardrailIdentifier": "gr-abc123",
|
||||
"guardrailVersion": "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Test the helper method directly
|
||||
converted_messages = config._convert_consecutive_user_messages_to_guarded_text(messages, optional_params)
|
||||
|
||||
# Verify the conversion
|
||||
assert len(converted_messages) == 1
|
||||
assert converted_messages[0]["role"] == "user"
|
||||
assert len(converted_messages[0]["content"]) == 2
|
||||
|
||||
# First element should be converted to guarded_text
|
||||
assert converted_messages[0]["content"][0]["type"] == "guarded_text"
|
||||
assert converted_messages[0]["content"][0]["text"] == "What is the main topic of this legal document?"
|
||||
|
||||
# Second element should remain unchanged
|
||||
assert converted_messages[0]["content"][1]["type"] == "image_url"
|
||||
assert converted_messages[0]["content"][1]["image_url"]["url"] == "https://example.com/image.jpg"
|
||||
|
||||
|
||||
def test_auto_convert_in_full_transformation():
|
||||
"""Test that the automatic conversion works in the full transformation pipeline."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "What is the main topic of this legal document?"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {
|
||||
"guardrailConfig": {
|
||||
"guardrailIdentifier": "gr-abc123",
|
||||
"guardrailVersion": "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Test the full transformation
|
||||
result = config._transform_request(
|
||||
model="anthropic.claude-3-sonnet-20240229-v1:0",
|
||||
messages=messages,
|
||||
optional_params=optional_params,
|
||||
litellm_params={},
|
||||
headers={}
|
||||
)
|
||||
|
||||
# Verify the transformation worked
|
||||
assert "messages" in result
|
||||
assert len(result["messages"]) == 1
|
||||
|
||||
# The message should have guardrailConverseContent
|
||||
message = result["messages"][0]
|
||||
assert "content" in message
|
||||
assert len(message["content"]) == 1
|
||||
assert "guardrailConverseContent" in message["content"][0]
|
||||
assert message["content"][0]["guardrailConverseContent"]["text"] == "What is the main topic of this legal document?"
|
||||
|
||||
|
||||
def test_convert_consecutive_user_messages_to_guarded_text():
|
||||
"""Test that consecutive user messages at the end are converted to guarded_text."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "First user message"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Assistant response"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Second user message"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Third user message"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {
|
||||
"guardrailConfig": {
|
||||
"guardrailIdentifier": "gr-abc123",
|
||||
"guardrailVersion": "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Test the helper method directly
|
||||
converted_messages = config._convert_consecutive_user_messages_to_guarded_text(messages, optional_params)
|
||||
|
||||
# Verify the conversion - only the last two user messages should be converted
|
||||
assert len(converted_messages) == 4
|
||||
|
||||
# First user message should remain unchanged
|
||||
assert converted_messages[0]["role"] == "user"
|
||||
assert converted_messages[0]["content"][0]["type"] == "text"
|
||||
assert converted_messages[0]["content"][0]["text"] == "First user message"
|
||||
|
||||
# Assistant message should remain unchanged
|
||||
assert converted_messages[1]["role"] == "assistant"
|
||||
assert converted_messages[1]["content"] == "Assistant response"
|
||||
|
||||
# Second user message should be converted to guarded_text
|
||||
assert converted_messages[2]["role"] == "user"
|
||||
assert converted_messages[2]["content"][0]["type"] == "guarded_text"
|
||||
assert converted_messages[2]["content"][0]["text"] == "Second user message"
|
||||
|
||||
# Third user message should be converted to guarded_text
|
||||
assert converted_messages[3]["role"] == "user"
|
||||
assert converted_messages[3]["content"][0]["type"] == "guarded_text"
|
||||
assert converted_messages[3]["content"][0]["text"] == "Third user message"
|
||||
|
||||
|
||||
def test_convert_all_user_messages_when_all_consecutive():
|
||||
"""Test that all user messages are converted when they are all consecutive at the end."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "First user message"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Second user message"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Third user message"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {
|
||||
"guardrailConfig": {
|
||||
"guardrailIdentifier": "gr-abc123",
|
||||
"guardrailVersion": "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Test the helper method directly
|
||||
converted_messages = config._convert_consecutive_user_messages_to_guarded_text(messages, optional_params)
|
||||
|
||||
# Verify all three user messages are converted
|
||||
assert len(converted_messages) == 3
|
||||
|
||||
for i in range(3):
|
||||
assert converted_messages[i]["role"] == "user"
|
||||
assert converted_messages[i]["content"][0]["type"] == "guarded_text"
|
||||
|
||||
assert converted_messages[0]["content"][0]["text"] == "First user message"
|
||||
assert converted_messages[1]["content"][0]["text"] == "Second user message"
|
||||
assert converted_messages[2]["content"][0]["text"] == "Third user message"
|
||||
|
||||
|
||||
def test_convert_consecutive_user_messages_with_string_content():
|
||||
"""Test that consecutive user messages with string content are converted to guarded_text."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Assistant response"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "First user message"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Second user message"
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {
|
||||
"guardrailConfig": {
|
||||
"guardrailIdentifier": "gr-abc123",
|
||||
"guardrailVersion": "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Test the helper method directly
|
||||
converted_messages = config._convert_consecutive_user_messages_to_guarded_text(messages, optional_params)
|
||||
|
||||
# Verify the conversion
|
||||
assert len(converted_messages) == 3
|
||||
|
||||
# Assistant message should remain unchanged
|
||||
assert converted_messages[0]["role"] == "assistant"
|
||||
assert converted_messages[0]["content"] == "Assistant response"
|
||||
|
||||
# Both user messages should be converted to guarded_text
|
||||
assert converted_messages[1]["role"] == "user"
|
||||
assert len(converted_messages[1]["content"]) == 1
|
||||
assert converted_messages[1]["content"][0]["type"] == "guarded_text"
|
||||
assert converted_messages[1]["content"][0]["text"] == "First user message"
|
||||
|
||||
assert converted_messages[2]["role"] == "user"
|
||||
assert len(converted_messages[2]["content"]) == 1
|
||||
assert converted_messages[2]["content"][0]["type"] == "guarded_text"
|
||||
assert converted_messages[2]["content"][0]["text"] == "Second user message"
|
||||
|
||||
|
||||
def test_skip_consecutive_user_messages_with_existing_guarded_text():
|
||||
"""Test that consecutive user messages with existing guarded_text are skipped."""
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "guarded_text",
|
||||
"text": "Already guarded"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Should be converted"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
optional_params = {
|
||||
"guardrailConfig": {
|
||||
"guardrailIdentifier": "gr-abc123",
|
||||
"guardrailVersion": "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Test the helper method directly
|
||||
converted_messages = config._convert_consecutive_user_messages_to_guarded_text(messages, optional_params)
|
||||
|
||||
# Verify the conversion
|
||||
assert len(converted_messages) == 2
|
||||
|
||||
# First message should remain unchanged (already has guarded_text)
|
||||
assert converted_messages[0]["role"] == "user"
|
||||
assert converted_messages[0]["content"][0]["type"] == "guarded_text"
|
||||
assert converted_messages[0]["content"][0]["text"] == "Already guarded"
|
||||
|
||||
# Second message should be converted
|
||||
assert converted_messages[1]["role"] == "user"
|
||||
assert converted_messages[1]["content"][0]["type"] == "guarded_text"
|
||||
assert converted_messages[1]["content"][0]["text"] == "Should be converted"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user