Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions python/semantic_kernel/contents/chat_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,26 +414,29 @@ def store_chat_history_to_file(self, file_path: str) -> None:
"""Stores the serialized ChatHistory to a file.

Uses mode "w" which means the file is created if it does not exist and gets truncated if it does.
The file is always written as UTF-8, so that histories with non-ASCII content can be stored
and reloaded on platforms whose locale encoding is not UTF-8.

Args:
file_path: The path to the file where the serialized data will be stored.
"""
json_str = self.serialize()
with open(file_path, "w") as local_file:
with open(file_path, "w", encoding="utf-8") as local_file:
local_file.write(json_str)

@classmethod
def load_chat_history_from_file(cls: type[_T], file_path: str) -> _T:
"""Loads the ChatHistory from a file.

Uses mode "r" which means it can only be read if it exists.
The file is always read as UTF-8, matching what store_chat_history_to_file writes.

Args:
file_path: The path to the file from which to load the ChatHistory.

Returns:
ChatHistory: The deserialized ChatHistory instance.
"""
with open(file_path) as file:
with open(file_path, encoding="utf-8") as file:
json_str = file.read()
return cls.restore_chat_history(json_str)
18 changes: 18 additions & 0 deletions python/tests/unit/contents/test_chat_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,24 @@ def test_to_from_file(chat_history: ChatHistory, tmp_path):
assert chat_history_2.messages[4] == chat_history.messages[4]


def test_to_from_file_non_ascii(chat_history: ChatHistory, tmp_path):
"""Chat histories with non-ASCII content should round-trip on any platform.

The file is always written and read as UTF-8, so the round-trip does not depend on the
locale encoding of the machine (which is not UTF-8 on Windows).
"""
chat_history.add_user_message("你好,今天天气怎么样?")
chat_history.add_assistant_message("À Paris, il fait beau ☀️")

file_path = tmp_path / "chat_history.json"
chat_history.store_chat_history_to_file(file_path)

assert "你好" in file_path.read_text(encoding="utf-8")

chat_history_2 = ChatHistory.load_chat_history_from_file(file_path)
assert chat_history_2.messages == chat_history.messages


def test_from_rendered_prompt_preserves_html_p_tag():
"""HTML <p> tags in prompts should be preserved as text, not treated as template tags.

Expand Down
Loading