mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix: preserve non-leading developer message order
This commit is contained in:
parent
079d6e40fd
commit
e656c4529c
2 changed files with 71 additions and 21 deletions
|
|
@ -218,28 +218,44 @@ def map_developer_role_to_system_role(
|
|||
if not any(m["role"] == "developer" for m in messages):
|
||||
return messages
|
||||
|
||||
system_message: Optional[Dict[str, Any]] = None
|
||||
system_contents: List[Any] = []
|
||||
non_system_messages: List[AllMessageValues] = []
|
||||
for m in messages:
|
||||
if m["role"] in {"developer", "system"}:
|
||||
if system_message is None:
|
||||
system_message = dict(m)
|
||||
system_message["role"] = "system"
|
||||
system_contents.append(m["content"])
|
||||
else:
|
||||
non_system_messages.append(m)
|
||||
new_messages: List[AllMessageValues] = []
|
||||
leading_system_message: Optional[Dict[str, Any]] = None
|
||||
leading_system_contents: List[Any] = []
|
||||
idx = 0
|
||||
|
||||
while idx < len(messages) and messages[idx]["role"] in {"developer", "system"}:
|
||||
m = messages[idx]
|
||||
if leading_system_message is None:
|
||||
leading_system_message = dict(m)
|
||||
leading_system_message["role"] = "system"
|
||||
leading_system_contents.append(m["content"])
|
||||
if m["role"] == "developer":
|
||||
verbose_logger.debug(
|
||||
"Translating developer role to system role for non-OpenAI providers."
|
||||
) # ensure user knows what's happening with their input.
|
||||
_log_developer_role_translation()
|
||||
idx += 1
|
||||
|
||||
if system_message is None:
|
||||
return non_system_messages
|
||||
if leading_system_message is not None:
|
||||
leading_system_message["content"] = _merge_system_message_contents(
|
||||
leading_system_contents
|
||||
)
|
||||
new_messages.append(cast(AllMessageValues, leading_system_message))
|
||||
|
||||
system_message["content"] = _merge_system_message_contents(system_contents)
|
||||
return [cast(AllMessageValues, system_message), *non_system_messages]
|
||||
for m in messages[idx:]:
|
||||
if m["role"] in {"developer", "system"}:
|
||||
if m["role"] == "developer":
|
||||
_log_developer_role_translation()
|
||||
new_messages.append(cast(AllMessageValues, {**m, "role": "system"}))
|
||||
else:
|
||||
new_messages.append(m)
|
||||
continue
|
||||
|
||||
new_messages.append(m)
|
||||
return new_messages
|
||||
|
||||
|
||||
def _log_developer_role_translation() -> None:
|
||||
verbose_logger.debug(
|
||||
"Translating developer role to system role for non-OpenAI providers."
|
||||
) # ensure user knows what's happening with their input.
|
||||
|
||||
|
||||
def _merge_system_message_contents(contents: List[Any]) -> Union[str, List[Any]]:
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ def test_map_developer_role_leaves_messages_without_developer_role_unchanged():
|
|||
assert map_developer_role_to_system_role(messages=messages) is messages
|
||||
|
||||
|
||||
def test_map_developer_role_merges_system_equivalent_messages():
|
||||
def test_map_developer_role_merges_leading_system_equivalent_messages():
|
||||
messages = [
|
||||
{"role": "system", "content": "Follow the product policy."},
|
||||
{"role": "developer", "content": "Prefer concise answers."},
|
||||
{"role": "user", "content": "Hello!"},
|
||||
{"role": "system", "content": "Use markdown only when helpful."},
|
||||
{"role": "user", "content": "Hello!"},
|
||||
]
|
||||
|
||||
result = map_developer_role_to_system_role(messages=messages)
|
||||
|
|
@ -36,9 +36,11 @@ def test_map_developer_role_merges_system_equivalent_messages():
|
|||
]
|
||||
|
||||
|
||||
def test_map_developer_role_preserves_structured_system_content():
|
||||
def test_map_developer_role_preserves_structured_leading_system_content():
|
||||
messages = [
|
||||
{"role": "developer", "content": ""},
|
||||
{"role": "system", "content": [{"type": "text", "text": "System rules."}]},
|
||||
{"role": "developer", "content": None},
|
||||
{"role": "developer", "content": "Developer rules."},
|
||||
{"role": "user", "content": "Hello!"},
|
||||
]
|
||||
|
|
@ -58,6 +60,38 @@ def test_map_developer_role_preserves_structured_system_content():
|
|||
]
|
||||
|
||||
|
||||
def test_map_developer_role_converts_later_developer_messages_in_place():
|
||||
messages = [
|
||||
{"role": "system", "content": "Follow the product policy."},
|
||||
{"role": "user", "content": "Hello!"},
|
||||
{"role": "developer", "content": "Prefer concise answers."},
|
||||
{"role": "assistant", "content": "Hi."},
|
||||
]
|
||||
|
||||
result = map_developer_role_to_system_role(messages=messages)
|
||||
|
||||
assert result == [
|
||||
{"role": "system", "content": "Follow the product policy."},
|
||||
{"role": "user", "content": "Hello!"},
|
||||
{"role": "system", "content": "Prefer concise answers."},
|
||||
{"role": "assistant", "content": "Hi."},
|
||||
]
|
||||
|
||||
|
||||
def test_map_developer_role_converts_later_developer_without_leading_system():
|
||||
messages = [
|
||||
{"role": "user", "content": "Hello!"},
|
||||
{"role": "developer", "content": "Prefer concise answers."},
|
||||
]
|
||||
|
||||
result = map_developer_role_to_system_role(messages=messages)
|
||||
|
||||
assert result == [
|
||||
{"role": "user", "content": "Hello!"},
|
||||
{"role": "system", "content": "Prefer concise answers."},
|
||||
]
|
||||
|
||||
|
||||
def test_responses_instructions_and_developer_input_become_single_system_message():
|
||||
request = LiteLLMCompletionResponsesConfig.transform_responses_api_request_to_chat_completion_request(
|
||||
model="anthropic/claude-sonnet-4-5",
|
||||
Loading…
Add table
Reference in a new issue