From 631bd20c3537ce85bbaec02f9e0049c88fa8fdd4 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 24 Mar 2026 17:46:33 -0500 Subject: [PATCH] refac --- backend/open_webui/utils/middleware.py | 5 +++++ backend/open_webui/utils/misc.py | 27 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 62c62833e..8379233c5 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -92,6 +92,7 @@ from open_webui.utils.misc import ( get_last_user_message_item, get_last_assistant_message, get_system_message, + merge_system_messages, replace_system_message_content, prepend_to_first_user_message_content, convert_logit_bias_input_to_json, @@ -2696,6 +2697,10 @@ async def process_chat_payload(request, form_data, user, metadata, model): # to prevent errors from providers like Gemini and Claude form_data['messages'] = strip_empty_content_blocks(form_data.get('messages', [])) + # Merge any duplicate system messages into a single message at position 0 + # to prevent template parsing errors with strict chat templates (e.g. Qwen) + form_data['messages'] = merge_system_messages(form_data.get('messages', [])) + return form_data, metadata, events diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py index e6b686071..bfa934c8b 100644 --- a/backend/open_webui/utils/misc.py +++ b/backend/open_webui/utils/misc.py @@ -330,6 +330,33 @@ def pop_system_message(messages: list[dict]) -> tuple[Optional[dict], list[dict] return get_system_message(messages), remove_system_message(messages) +def merge_system_messages(messages: list[dict]) -> list[dict]: + """ + Merge all system messages into one at position 0. + + Some chat templates (e.g. Qwen) require exactly one system + message at the start. Multiple pipeline stages may each + insert their own system message; this function consolidates + them. + """ + system_contents: list[str] = [] + other_messages: list[dict] = [] + + for message in messages: + if message.get('role') == 'system': + content = get_content_from_message(message) + if content: + system_contents.append(content) + else: + other_messages.append(message) + + if not system_contents: + return other_messages + + merged = {'role': 'system', 'content': '\n'.join(system_contents)} + return [merged, *other_messages] + + def update_message_content(message: dict, content: str, append: bool = True) -> dict: if isinstance(message['content'], list): for item in message['content']: