mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-20 05:04:24 +00:00
Fix map_system_message_pt for content-block list messages
map_system_message_pt (used by supports_system_message=False) merged the system prompt into the next message with string concatenation, raising 'TypeError: can only concatenate list (not "str") to list' whenever the system or user content was a list of content blocks - the format sent by Anthropic-style clients (e.g. Claude Code / Agent SDK) through the /v1/messages endpoint. Merge as a list of content blocks when either side is a list; keep the existing string behavior otherwise. Adds regression tests.
This commit is contained in:
parent
3d63edaa6d
commit
e45ab7c774
2 changed files with 73 additions and 2 deletions
|
|
@ -87,6 +87,13 @@ DEFAULT_ASSISTANT_CONTINUE_MESSAGE = ChatCompletionAssistantMessage(
|
|||
) # similar to autogen. Only used if `litellm.modify_params=True`.
|
||||
|
||||
|
||||
def _content_as_block_list(content) -> list:
|
||||
"""Normalize a message content field to a list of content blocks."""
|
||||
if isinstance(content, list):
|
||||
return content
|
||||
return [{"type": "text", "text": content}]
|
||||
|
||||
|
||||
def map_system_message_pt(messages: list) -> list:
|
||||
"""
|
||||
Convert 'system' message to 'user' message if provider doesn't support 'system' role.
|
||||
|
|
@ -105,8 +112,17 @@ def map_system_message_pt(messages: list) -> list:
|
|||
next_m = messages[i + 1]
|
||||
next_role = next_m["role"]
|
||||
if next_role == "user" or next_role == "assistant": # Next message is a user or assistant message
|
||||
# Merge system prompt into the next message
|
||||
next_m["content"] = m["content"] + " " + next_m["content"]
|
||||
# Merge system prompt into the next message. Contents may be
|
||||
# strings or lists of content blocks (e.g. Anthropic-style
|
||||
# requests); merge as block lists when either side is a list.
|
||||
if isinstance(m["content"], list) or isinstance(
|
||||
next_m["content"], list
|
||||
):
|
||||
next_m["content"] = _content_as_block_list(
|
||||
m["content"]
|
||||
) + _content_as_block_list(next_m["content"])
|
||||
else:
|
||||
next_m["content"] = m["content"] + " " + next_m["content"]
|
||||
elif next_role == "system": # Next message is a system message
|
||||
# Append a user message instead of the system message
|
||||
new_message = {"role": "user", "content": m["content"]}
|
||||
|
|
|
|||
|
|
@ -3166,3 +3166,58 @@ async def test_bedrock_converse_message_level_cache_point_preserves_ttl_async():
|
|||
)
|
||||
|
||||
assert _collect_cache_points(result) == [{"type": "default", "ttl": "1h"}]
|
||||
|
||||
|
||||
def test_map_system_message_pt_string_contents():
|
||||
"""Baseline: string contents keep the existing merge behavior."""
|
||||
from litellm.litellm_core_utils.prompt_templates.factory import (
|
||||
map_system_message_pt,
|
||||
)
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": "You are helpful."},
|
||||
{"role": "user", "content": "Hi"},
|
||||
]
|
||||
result = map_system_message_pt(messages=messages)
|
||||
assert result == [{"role": "user", "content": "You are helpful. Hi"}]
|
||||
|
||||
|
||||
def test_map_system_message_pt_content_block_lists():
|
||||
"""Contents sent as content-block lists (e.g. Anthropic-style requests)
|
||||
must not raise 'can only concatenate list (not "str") to list'.
|
||||
Regression test for supports_system_message=False with block content."""
|
||||
from litellm.litellm_core_utils.prompt_templates.factory import (
|
||||
map_system_message_pt,
|
||||
)
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": [{"type": "text", "text": "You are helpful."}],
|
||||
},
|
||||
{"role": "user", "content": [{"type": "text", "text": "Hi"}]},
|
||||
]
|
||||
result = map_system_message_pt(messages=messages)
|
||||
assert len(result) == 1
|
||||
assert result[0]["role"] == "user"
|
||||
assert result[0]["content"] == [
|
||||
{"type": "text", "text": "You are helpful."},
|
||||
{"type": "text", "text": "Hi"},
|
||||
]
|
||||
|
||||
|
||||
def test_map_system_message_pt_mixed_contents():
|
||||
"""String system content merged into a block-list user message."""
|
||||
from litellm.litellm_core_utils.prompt_templates.factory import (
|
||||
map_system_message_pt,
|
||||
)
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": "You are helpful."},
|
||||
{"role": "user", "content": [{"type": "text", "text": "Hi"}]},
|
||||
]
|
||||
result = map_system_message_pt(messages=messages)
|
||||
assert result[0]["content"] == [
|
||||
{"type": "text", "text": "You are helpful."},
|
||||
{"type": "text", "text": "Hi"},
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue