Skip to content

Commit 887b2e2

Browse files
authored
Add support for empty assitant message in between messages (#15850)
1 parent ef2000b commit 887b2e2

File tree

2 files changed

+98
-2
lines changed

2 files changed

+98
-2
lines changed

litellm/litellm_core_utils/prompt_templates/factory.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3811,7 +3811,9 @@ def _bedrock_converse_messages_pt( # noqa: PLR0915
38113811
assistant_parts=assistants_parts,
38123812
)
38133813
elif element["type"] == "text":
3814-
assistants_part = BedrockContentBlock(text=element["text"])
3814+
# AWS Bedrock doesn't allow empty or whitespace-only text content, so use placeholder for empty strings
3815+
text_content = element["text"] if element["text"].strip() else "."
3816+
assistants_part = BedrockContentBlock(text=text_content)
38153817
assistants_parts.append(assistants_part)
38163818
elif element["type"] == "image_url":
38173819
if isinstance(element["image_url"], dict):
@@ -3835,7 +3837,9 @@ def _bedrock_converse_messages_pt( # noqa: PLR0915
38353837
assistants_parts.append(_cache_point_block)
38363838
assistant_content.extend(assistants_parts)
38373839
elif _assistant_content is not None and isinstance(_assistant_content, str):
3838-
assistant_content.append(BedrockContentBlock(text=_assistant_content))
3840+
# AWS Bedrock doesn't allow empty or whitespace-only text content, so use placeholder for empty strings
3841+
text_content = _assistant_content if _assistant_content.strip() else "."
3842+
assistant_content.append(BedrockContentBlock(text=text_content))
38393843
# Add cache point block for assistant string content
38403844
_cache_point_block = (
38413845
litellm.AmazonConverseConfig()._get_cache_point_block(

tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2584,3 +2584,95 @@ def test_request_metadata_not_provided():
25842584

25852585
# requestMetadata should not be in the request
25862586
assert "requestMetadata" not in request_data
2587+
2588+
2589+
def test_empty_assistant_message_handling():
2590+
"""
2591+
Test that empty assistant messages are handled correctly by replacing
2592+
empty or whitespace-only content with a placeholder to prevent AWS Bedrock
2593+
Converse API 400 Bad Request errors.
2594+
"""
2595+
from litellm.litellm_core_utils.prompt_templates.factory import _bedrock_converse_messages_pt
2596+
2597+
# Test case 1: Empty string content - test with modify_params=True to prevent merging
2598+
messages = [
2599+
{"role": "user", "content": "Hello"},
2600+
{"role": "assistant", "content": ""}, # Empty content
2601+
{"role": "user", "content": "How are you?"}
2602+
]
2603+
2604+
# Enable modify_params to prevent consecutive user message merging
2605+
original_modify_params = litellm.modify_params
2606+
litellm.modify_params = True
2607+
2608+
try:
2609+
result = _bedrock_converse_messages_pt(
2610+
messages=messages,
2611+
model="anthropic.claude-3-5-sonnet-20240620-v1:0",
2612+
llm_provider="bedrock_converse"
2613+
)
2614+
2615+
# Should have 3 messages: user, assistant (with placeholder), user
2616+
assert len(result) == 3
2617+
assert result[0]["role"] == "user"
2618+
assert result[1]["role"] == "assistant"
2619+
assert result[2]["role"] == "user"
2620+
2621+
# Assistant message should have placeholder text instead of empty content
2622+
assert len(result[1]["content"]) == 1
2623+
assert result[1]["content"][0]["text"] == "Please continue."
2624+
2625+
# Test case 2: Whitespace-only content
2626+
messages = [
2627+
{"role": "user", "content": "Hello"},
2628+
{"role": "assistant", "content": " "}, # Whitespace-only content
2629+
{"role": "user", "content": "How are you?"}
2630+
]
2631+
2632+
result = _bedrock_converse_messages_pt(
2633+
messages=messages,
2634+
model="anthropic.claude-3-5-sonnet-20240620-v1:0",
2635+
llm_provider="bedrock_converse"
2636+
)
2637+
2638+
# Assistant message should have placeholder text instead of whitespace
2639+
assert len(result[1]["content"]) == 1
2640+
assert result[1]["content"][0]["text"] == "Please continue."
2641+
2642+
# Test case 3: Empty list content
2643+
messages = [
2644+
{"role": "user", "content": "Hello"},
2645+
{"role": "assistant", "content": [{"type": "text", "text": ""}]}, # Empty text in list
2646+
{"role": "user", "content": "How are you?"}
2647+
]
2648+
2649+
result = _bedrock_converse_messages_pt(
2650+
messages=messages,
2651+
model="anthropic.claude-3-5-sonnet-20240620-v1:0",
2652+
llm_provider="bedrock_converse"
2653+
)
2654+
2655+
# Assistant message should have placeholder text instead of empty text
2656+
assert len(result[1]["content"]) == 1
2657+
assert result[1]["content"][0]["text"] == "Please continue."
2658+
2659+
# Test case 4: Normal content should not be affected
2660+
messages = [
2661+
{"role": "user", "content": "Hello"},
2662+
{"role": "assistant", "content": "I'm doing well, thank you!"}, # Normal content
2663+
{"role": "user", "content": "How are you?"}
2664+
]
2665+
2666+
result = _bedrock_converse_messages_pt(
2667+
messages=messages,
2668+
model="anthropic.claude-3-5-sonnet-20240620-v1:0",
2669+
llm_provider="bedrock_converse"
2670+
)
2671+
2672+
# Assistant message should keep original content
2673+
assert len(result[1]["content"]) == 1
2674+
assert result[1]["content"][0]["text"] == "I'm doing well, thank you!"
2675+
2676+
finally:
2677+
# Restore original modify_params setting
2678+
litellm.modify_params = original_modify_params

0 commit comments

Comments
 (0)