mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix(factory): merge system message into content-block lists without string concat
This commit is contained in:
parent
a4199d3c09
commit
a760798283
2 changed files with 76 additions and 1 deletions
|
|
@ -87,6 +87,18 @@ DEFAULT_ASSISTANT_CONTINUE_MESSAGE = ChatCompletionAssistantMessage(
|
|||
) # similar to autogen. Only used if `litellm.modify_params=True`.
|
||||
|
||||
|
||||
def _merge_message_content(system_content: Union[str, list], next_content: Union[str, list]) -> Union[str, list]:
|
||||
if isinstance(system_content, str) and isinstance(next_content, str):
|
||||
return system_content + " " + next_content
|
||||
|
||||
def as_blocks(content: Union[str, list]) -> list:
|
||||
if isinstance(content, str):
|
||||
return [{"type": "text", "text": content}]
|
||||
return list(content)
|
||||
|
||||
return as_blocks(system_content) + as_blocks(next_content)
|
||||
|
||||
|
||||
def map_system_message_pt(messages: list) -> list:
|
||||
"""
|
||||
Convert 'system' message to 'user' message if provider doesn't support 'system' role.
|
||||
|
|
@ -106,7 +118,7 @@ def map_system_message_pt(messages: list) -> list:
|
|||
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"]
|
||||
next_m["content"] = _merge_message_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"]}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,69 @@ def test_supports_system_message():
|
|||
assert isinstance(response, litellm.ModelResponse)
|
||||
|
||||
|
||||
def test_map_system_message_pt_content_block_lists():
|
||||
"""
|
||||
Regression for https://github.com/BerriAI/litellm/issues/32904
|
||||
|
||||
When system and/or user content is a list of content blocks (Anthropic-style),
|
||||
merging must not string-concatenate a list. Merge as a block list instead.
|
||||
"""
|
||||
messages = [
|
||||
{"role": "system", "content": [{"type": "text", "text": "Be brief."}]},
|
||||
{"role": "user", "content": [{"type": "text", "text": "Hi"}]},
|
||||
]
|
||||
|
||||
new_messages = map_system_message_pt(messages=messages)
|
||||
|
||||
assert len(new_messages) == 1
|
||||
assert new_messages[0]["role"] == "user"
|
||||
assert new_messages[0]["content"] == [
|
||||
{"type": "text", "text": "Be brief."},
|
||||
{"type": "text", "text": "Hi"},
|
||||
]
|
||||
|
||||
|
||||
def test_map_system_message_pt_mixed_string_and_content_blocks():
|
||||
"""
|
||||
Mixed forms: a plain string on one side and a content-block list on the other
|
||||
should merge into a block list rather than raising.
|
||||
"""
|
||||
system_list_user_str = map_system_message_pt(
|
||||
messages=[
|
||||
{"role": "system", "content": [{"type": "text", "text": "Be brief."}]},
|
||||
{"role": "user", "content": "Hi"},
|
||||
]
|
||||
)
|
||||
assert system_list_user_str[0]["content"] == [
|
||||
{"type": "text", "text": "Be brief."},
|
||||
{"type": "text", "text": "Hi"},
|
||||
]
|
||||
|
||||
system_str_user_list = map_system_message_pt(
|
||||
messages=[
|
||||
{"role": "system", "content": "Be brief."},
|
||||
{"role": "user", "content": [{"type": "text", "text": "Hi"}]},
|
||||
]
|
||||
)
|
||||
assert system_str_user_list[0]["content"] == [
|
||||
{"type": "text", "text": "Be brief."},
|
||||
{"type": "text", "text": "Hi"},
|
||||
]
|
||||
|
||||
|
||||
def test_map_system_message_pt_string_content_unchanged():
|
||||
"""
|
||||
Plain string content on both sides keeps the original space-joined behavior.
|
||||
"""
|
||||
new_messages = map_system_message_pt(
|
||||
messages=[
|
||||
{"role": "system", "content": "Be brief."},
|
||||
{"role": "user", "content": "Hi"},
|
||||
]
|
||||
)
|
||||
assert new_messages[0]["content"] == "Be brief. Hi"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"stop_sequence, expected_count", [("\n", 0), (["\n"], 0), (["finish_reason"], 1)]
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue