diff --git a/libs/core/langchain_core/chat_history.py b/libs/core/langchain_core/chat_history.py index 6f66b7aba75..774865a8b02 100644 --- a/libs/core/langchain_core/chat_history.py +++ b/libs/core/langchain_core/chat_history.py @@ -65,33 +65,43 @@ class BaseChatMessageHistory(ABC): .. code-block:: python + import json + import os + from langchain_core.messages import messages_from_dict, message_to_dict + + class FileChatMessageHistory(BaseChatMessageHistory): storage_path: str session_id: str @property - def messages(self): - with open( - os.path.join(storage_path, session_id), - "r", - encoding="utf-8", - ) as f: - messages = json.loads(f.read()) - return messages_from_dict(messages) + def messages(self) -> list[BaseMessage]: + try: + with open( + os.path.join(self.storage_path, self.session_id), + "r", + encoding="utf-8", + ) as f: + messages_data = json.load(f) + return messages_from_dict(messages_data) + except FileNotFoundError: + return [] def add_messages(self, messages: Sequence[BaseMessage]) -> None: all_messages = list(self.messages) # Existing messages all_messages.extend(messages) # Add new messages serialized = [message_to_dict(message) for message in all_messages] - # Can be further optimized by only writing new messages - # using append mode. - with open(os.path.join(storage_path, session_id), "w") as f: - json.dump(messages, f) + file_path = os.path.join(self.storage_path, self.session_id) + os.makedirs(os.path.dirname(file_path), exist_ok=True) + with open(file_path, "w", encoding="utf-8") as f: + json.dump(serialized, f) - def clear(self): - with open(os.path.join(storage_path, session_id), "w") as f: - f.write("[]") + def clear(self) -> None: + file_path = os.path.join(self.storage_path, self.session_id) + os.makedirs(os.path.dirname(file_path), exist_ok=True) + with open(file_path, "w", encoding="utf-8") as f: + json.dump([], f) """ diff --git a/libs/core/langchain_core/stores.py b/libs/core/langchain_core/stores.py index 939be003748..df9a78f9b48 100644 --- a/libs/core/langchain_core/stores.py +++ b/libs/core/langchain_core/stores.py @@ -59,7 +59,7 @@ class BaseStore(ABC, Generic[K, V]): def __init__(self) -> None: self.store: dict[str, int] = {} - def mget(self, keys: Sequence[str]) -> list[Optional[int]]: + def mget(self, keys: Sequence[str]) -> list[int | None]: return [self.store.get(key) for key in keys] def mset(self, key_value_pairs: Sequence[tuple[str, int]]) -> None: @@ -71,7 +71,7 @@ class BaseStore(ABC, Generic[K, V]): if key in self.store: del self.store[key] - def yield_keys(self, prefix: Optional[str] = None) -> Iterator[str]: + def yield_keys(self, prefix: str | None = None) -> Iterator[str]: if prefix is None: yield from self.store.keys() else: diff --git a/libs/core/uv.lock b/libs/core/uv.lock index d06dd543ca3..f3a23b8235a 100644 --- a/libs/core/uv.lock +++ b/libs/core/uv.lock @@ -1174,7 +1174,7 @@ test = [{ name = "langchain-core", editable = "." }] test-integration = [] typing = [ { name = "langchain-core", editable = "." }, - { name = "mypy", specifier = ">=1.17.1,<1.18" }, + { name = "mypy", specifier = ">=1.18.1,<1.19" }, { name = "types-pyyaml", specifier = ">=6.0.12.2,<7.0.0.0" }, ] @@ -1220,7 +1220,7 @@ test-integration = [ typing = [ { name = "beautifulsoup4", specifier = ">=4.13.5,<5.0.0" }, { name = "lxml-stubs", specifier = ">=0.5.1,<1.0.0" }, - { name = "mypy", specifier = ">=1.17.1,<1.18" }, + { name = "mypy", specifier = ">=1.18.1,<1.19" }, { name = "tiktoken", specifier = ">=0.11.0,<1.0.0" }, { name = "types-requests", specifier = ">=2.31.0.20240218,<3.0.0.0" }, ]