) — serialize it back
+ # to XML so the original content is preserved in the prompt text.
+ # This fixes #13632 where HTML tags caused content to be silently dropped.
+ # Note: tostring() includes the element's tail, so we don't add it separately.
+ pending_text_parts.append(tostring(item, encoding="unicode"))
+
+ # Flush any remaining text (as USER if messages exist, SYSTEM otherwise)
+ flush_pending_text(role=AuthorRole.USER if messages else AuthorRole.SYSTEM)
if len(messages) == 1 and messages[0].role == AuthorRole.SYSTEM:
messages[0].role = AuthorRole.USER
return cls(messages=messages)
diff --git a/python/tests/unit/contents/test_chat_history.py b/python/tests/unit/contents/test_chat_history.py
index ac41949a7325..b993116ec4f6 100644
--- a/python/tests/unit/contents/test_chat_history.py
+++ b/python/tests/unit/contents/test_chat_history.py
@@ -592,6 +592,48 @@ async def test_template_empty_history(chat_history: ChatHistory):
assert chat_history_2.messages[1].role == AuthorRole.USER
+def test_chat_history_from_rendered_prompt_with_html_tags():
+ """Regression test for #13632: HTML tags in prompts caused content to be dropped.
+
+ When the prompt contains valid XML tags like
, etc., the XML parser
+ was treating them as elements and silently discarding their content because
+ they weren't recognized as chat message tags. The fix serializes unrecognized
+ elements back to their string representation.
+ """
+ # Prompt with HTML-like tags
+ prompt_with_html = 'Translate this: "
What is your name?
"'
+ # Same prompt without HTML tags
+ prompt_without_html = 'Translate this: "What is your name?"'
+
+ history_with_html = ChatHistory.from_rendered_prompt(prompt_with_html)
+ history_without_html = ChatHistory.from_rendered_prompt(prompt_without_html)
+
+ # Both should produce a single user message
+ assert len(history_with_html.messages) == 1
+ assert len(history_without_html.messages) == 1
+
+ # Both should contain the question text
+ assert "What is your name?" in history_with_html.messages[0].content
+ assert "What is your name?" in history_without_html.messages[0].content
+
+ # The HTML version should preserve the
tags
+ assert "
" in history_with_html.messages[0].content
+ assert "
" in history_with_html.messages[0].content
+
+
+def test_chat_history_from_rendered_prompt_with_nested_html():
+ """Test that nested HTML-like tags are preserved."""
+ prompt = "Format this:
"
+
+ history = ChatHistory.from_rendered_prompt(prompt)
+
+ assert len(history.messages) == 1
+ assert "Hello" in history.messages[0].content
+ assert "World" in history.messages[0].content
+ assert "
" in history.messages[0].content
+ assert "
" in history.messages[0].content
+
+
def test_to_from_file(chat_history: ChatHistory, tmp_path):
chat_history.add_system_message("You are an AI assistant")
chat_history.add_user_message("What is the weather in Seattle?")