def _ensure_system_first(messages: list[PromptMessage]) -> list[PromptMessage]: """Qwen3/vLLM chat templates accept ONLY one system message, at the start. Dify (esp. Agent apps) stacks several system/developer prompts: KB assistant prompt + agent tool prompt + an empty system + config manifest... Merging them into a single system message (joined by blank lines, empties dropped) keeps it at the front; every other message keeps its original relative order. """ system_parts: list[str] = [] rest: list[PromptMessage] = [] for m in messages: if isinstance(m, (SystemPromptMessage, DeveloperPromptMessage)): text = _text_content(m) if text.strip(): system_parts.append(text) else: rest.append(m) if system_parts: rest.insert(0, SystemPromptMessage(content="\n\n".join(system_parts))) return rest