From c8c88a6436aab005b29b006bd36714e1328a078c Mon Sep 17 00:00:00 2001 From: iamzimozic Date: Wed, 8 Oct 2025 15:14:55 +0530 Subject: [PATCH 01/10] fix(chatstore): handle FunctionCall serialization in PostgresChatStore (#19992) --- .../storage/chat_store/postgres/base.py | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py index 7f814535a3..6058f25ea7 100644 --- a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py +++ b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py @@ -18,6 +18,19 @@ from llama_index.core.bridge.pydantic import Field, PrivateAttr from llama_index.core.storage.chat_store.base import BaseChatStore +import json + +def safe_model_dump_json(model): + """ + Safely dumps a Pydantic model to JSON, even if it contains + non-serializable objects like Google FunctionCall. + """ + try: + return model.model_dump_json(exclude_none=True) + except Exception: + data = model.model_dump(exclude_none=True) + return json.dumps(data, default=lambda o: getattr(o, "__dict__", str(o))) + def get_data_model( base: type, @@ -192,7 +205,7 @@ def set_messages(self, key: str, messages: list[ChatMessage]) -> None: params = { "key": key, - "value": [message.model_dump_json() for message in messages], + "value": [safe_model_dump_json(message) for message in messages], } # Execute the bulk upsert @@ -214,7 +227,7 @@ async def aset_messages(self, key: str, messages: list[ChatMessage]) -> None: params = { "key": key, - "value": [message.model_dump_json() for message in messages], + "value": [safe_model_dump_json(message) for message in messages], } # Execute the bulk upsert @@ -257,7 +270,7 @@ def add_message(self, key: str, message: ChatMessage) -> None: value = array_cat({self._table_class.__tablename__}.value, :value); """ ) - params = {"key": key, "value": [message.model_dump_json()]} + params = {"key": key, "value": [safe_model_dump_json(message)]} session.execute(stmt, params) session.commit() @@ -273,7 +286,7 @@ async def async_add_message(self, key: str, message: ChatMessage) -> None: value = array_cat({self._table_class.__tablename__}.value, :value); """ ) - params = {"key": key, "value": [message.model_dump_json()]} + params = {"key": key, "value": [safe_model_dump_json(message)]} await session.execute(stmt, params) await session.commit() From d35b43ace7ce77b8e9fcfee525f8a52bfcd48579 Mon Sep 17 00:00:00 2001 From: iamzimozic Date: Wed, 8 Oct 2025 15:08:21 +0000 Subject: [PATCH 02/10] fix --- .../llama_index/storage/chat_store/postgres/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py index 6058f25ea7..65516e74cd 100644 --- a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py +++ b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py @@ -20,6 +20,7 @@ import json + def safe_model_dump_json(model): """ Safely dumps a Pydantic model to JSON, even if it contains From d24bbd61bd31f26e1be66e328ed868b9ba68c09e Mon Sep 17 00:00:00 2001 From: iamzimozic Date: Wed, 8 Oct 2025 17:26:59 +0000 Subject: [PATCH 03/10] fix --- .github/workflows/core-typecheck.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/core-typecheck.yml b/.github/workflows/core-typecheck.yml index 15f63a337f..acafb21b8f 100644 --- a/.github/workflows/core-typecheck.yml +++ b/.github/workflows/core-typecheck.yml @@ -14,6 +14,11 @@ jobs: with: fetch-depth: 1 + - name: Install Pillow dependencies + run: | + sudo apt-get update + sudo apt-get install -y libjpeg-dev zlib1g-dev freetype-dev # freetype for font support, just in case + - name: Install uv uses: astral-sh/setup-uv@v7 From 3ebaee0d8f8b283520f8f38d7c3752412adfcb9e Mon Sep 17 00:00:00 2001 From: Logan Markewich Date: Wed, 8 Oct 2025 12:24:45 -0600 Subject: [PATCH 04/10] revert changes to workflow --- .github/workflows/core-typecheck.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/core-typecheck.yml b/.github/workflows/core-typecheck.yml index acafb21b8f..15f63a337f 100644 --- a/.github/workflows/core-typecheck.yml +++ b/.github/workflows/core-typecheck.yml @@ -14,11 +14,6 @@ jobs: with: fetch-depth: 1 - - name: Install Pillow dependencies - run: | - sudo apt-get update - sudo apt-get install -y libjpeg-dev zlib1g-dev freetype-dev # freetype for font support, just in case - - name: Install uv uses: astral-sh/setup-uv@v7 From 33d0c3390753ab5202bacaf3154e3e3eee852254 Mon Sep 17 00:00:00 2001 From: Logan Markewich Date: Wed, 8 Oct 2025 12:25:18 -0600 Subject: [PATCH 05/10] bump package version --- .../llama-index-storage-chat-store-postgres/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/pyproject.toml b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/pyproject.toml index 7f8bbd4303..5157e953dd 100644 --- a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/pyproject.toml +++ b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/pyproject.toml @@ -28,7 +28,7 @@ dev = [ [project] name = "llama-index-storage-chat-store-postgres" -version = "0.3.1" +version = "0.3.2" description = "llama-index storage-chat-store postgres integration" authors = [{name = "Your Name", email = "you@example.com"}] requires-python = ">=3.9,<4.0" From 5ff1760942eff5670515066a492cfa0663710c41 Mon Sep 17 00:00:00 2001 From: iamzimozic Date: Wed, 8 Oct 2025 18:46:08 +0000 Subject: [PATCH 06/10] fix --- .../llama_index/core/base/llms/types.py | 4 ++++ .../storage/chat_store/postgres/base.py | 22 ++++--------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/llama-index-core/llama_index/core/base/llms/types.py b/llama-index-core/llama_index/core/base/llms/types.py index 479f4c0df3..2f67c9dadf 100644 --- a/llama-index-core/llama_index/core/base/llms/types.py +++ b/llama-index-core/llama_index/core/base/llms/types.py @@ -35,6 +35,7 @@ from llama_index.core.constants import DEFAULT_CONTEXT_WINDOW, DEFAULT_NUM_OUTPUTS from llama_index.core.schema import ImageDocument from llama_index.core.utils import resolve_binary +from google.protobuf.json_format import MessageToDict class MessageRole(str, Enum): @@ -562,6 +563,9 @@ def _recursive_serialization(self, value: Any) -> Any: if isinstance(value, bytes): return base64.b64encode(value).decode("utf-8") + if hasattr(value, "_pb") and hasattr(value._pb, "DESCRIPTOR"): + return MessageToDict(value, preserving_proto_field_name=True) + return value @field_serializer("additional_kwargs", check_fields=False) diff --git a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py index 65516e74cd..7f814535a3 100644 --- a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py +++ b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py @@ -18,20 +18,6 @@ from llama_index.core.bridge.pydantic import Field, PrivateAttr from llama_index.core.storage.chat_store.base import BaseChatStore -import json - - -def safe_model_dump_json(model): - """ - Safely dumps a Pydantic model to JSON, even if it contains - non-serializable objects like Google FunctionCall. - """ - try: - return model.model_dump_json(exclude_none=True) - except Exception: - data = model.model_dump(exclude_none=True) - return json.dumps(data, default=lambda o: getattr(o, "__dict__", str(o))) - def get_data_model( base: type, @@ -206,7 +192,7 @@ def set_messages(self, key: str, messages: list[ChatMessage]) -> None: params = { "key": key, - "value": [safe_model_dump_json(message) for message in messages], + "value": [message.model_dump_json() for message in messages], } # Execute the bulk upsert @@ -228,7 +214,7 @@ async def aset_messages(self, key: str, messages: list[ChatMessage]) -> None: params = { "key": key, - "value": [safe_model_dump_json(message) for message in messages], + "value": [message.model_dump_json() for message in messages], } # Execute the bulk upsert @@ -271,7 +257,7 @@ def add_message(self, key: str, message: ChatMessage) -> None: value = array_cat({self._table_class.__tablename__}.value, :value); """ ) - params = {"key": key, "value": [safe_model_dump_json(message)]} + params = {"key": key, "value": [message.model_dump_json()]} session.execute(stmt, params) session.commit() @@ -287,7 +273,7 @@ async def async_add_message(self, key: str, message: ChatMessage) -> None: value = array_cat({self._table_class.__tablename__}.value, :value); """ ) - params = {"key": key, "value": [safe_model_dump_json(message)]} + params = {"key": key, "value": [message.model_dump_json()]} await session.execute(stmt, params) await session.commit() From 28c6fd5005c45c55a4df1b61a754f88ec5cd1d7e Mon Sep 17 00:00:00 2001 From: iamzimozic Date: Wed, 8 Oct 2025 19:04:34 +0000 Subject: [PATCH 07/10] fix --- llama-index-core/pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/llama-index-core/pyproject.toml b/llama-index-core/pyproject.toml index 4ffe1143a7..c5ddf7766c 100644 --- a/llama-index-core/pyproject.toml +++ b/llama-index-core/pyproject.toml @@ -73,6 +73,7 @@ dependencies = [ "PyYAML>=6.0.1", "wrapt", "pydantic>=2.8.0", + "protobuf>=3.20.3,<5.0.0", "filetype>=1.2.0,<2", "eval-type-backport>=0.2.0,<0.3 ; python_version < '3.10'", "banks>=2.2.0,<3", From 051fbef8453c933efb2cc9a6814a12196bfae954 Mon Sep 17 00:00:00 2001 From: iamzimozic Date: Wed, 8 Oct 2025 19:47:27 +0000 Subject: [PATCH 08/10] fix --- llama-index-core/pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llama-index-core/pyproject.toml b/llama-index-core/pyproject.toml index c5ddf7766c..96e57b58ec 100644 --- a/llama-index-core/pyproject.toml +++ b/llama-index-core/pyproject.toml @@ -74,6 +74,8 @@ dependencies = [ "wrapt", "pydantic>=2.8.0", "protobuf>=3.20.3,<5.0.0", + "grpcio>=1.53.0,<2.0.0", + "grpcio-health-checking>=1.53.0,<2.0.0", "filetype>=1.2.0,<2", "eval-type-backport>=0.2.0,<0.3 ; python_version < '3.10'", "banks>=2.2.0,<3", From 82497dc8d083f3720718341cb3a6deb0d957d66b Mon Sep 17 00:00:00 2001 From: iamzimozic <120317711+iamzimozic@users.noreply.github.com> Date: Thu, 9 Oct 2025 01:57:00 +0530 Subject: [PATCH 09/10] Fix --- llama-index-core/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llama-index-core/pyproject.toml b/llama-index-core/pyproject.toml index 96e57b58ec..5856d181fb 100644 --- a/llama-index-core/pyproject.toml +++ b/llama-index-core/pyproject.toml @@ -73,7 +73,7 @@ dependencies = [ "PyYAML>=6.0.1", "wrapt", "pydantic>=2.8.0", - "protobuf>=3.20.3,<5.0.0", + "protobuf>=3.20.3,<4.23.4", "grpcio>=1.53.0,<2.0.0", "grpcio-health-checking>=1.53.0,<2.0.0", "filetype>=1.2.0,<2", From 66a65b53cfbfaa883c833763766c3b66c085bf08 Mon Sep 17 00:00:00 2001 From: iamzimozic Date: Thu, 9 Oct 2025 07:48:21 +0000 Subject: [PATCH 10/10] fix --- .../llama_index/core/base/llms/types.py | 4 ---- llama-index-core/pyproject.toml | 3 --- .../storage/chat_store/postgres/base.py | 22 +++++++++++++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/llama-index-core/llama_index/core/base/llms/types.py b/llama-index-core/llama_index/core/base/llms/types.py index 2f67c9dadf..479f4c0df3 100644 --- a/llama-index-core/llama_index/core/base/llms/types.py +++ b/llama-index-core/llama_index/core/base/llms/types.py @@ -35,7 +35,6 @@ from llama_index.core.constants import DEFAULT_CONTEXT_WINDOW, DEFAULT_NUM_OUTPUTS from llama_index.core.schema import ImageDocument from llama_index.core.utils import resolve_binary -from google.protobuf.json_format import MessageToDict class MessageRole(str, Enum): @@ -563,9 +562,6 @@ def _recursive_serialization(self, value: Any) -> Any: if isinstance(value, bytes): return base64.b64encode(value).decode("utf-8") - if hasattr(value, "_pb") and hasattr(value._pb, "DESCRIPTOR"): - return MessageToDict(value, preserving_proto_field_name=True) - return value @field_serializer("additional_kwargs", check_fields=False) diff --git a/llama-index-core/pyproject.toml b/llama-index-core/pyproject.toml index 5856d181fb..4ffe1143a7 100644 --- a/llama-index-core/pyproject.toml +++ b/llama-index-core/pyproject.toml @@ -73,9 +73,6 @@ dependencies = [ "PyYAML>=6.0.1", "wrapt", "pydantic>=2.8.0", - "protobuf>=3.20.3,<4.23.4", - "grpcio>=1.53.0,<2.0.0", - "grpcio-health-checking>=1.53.0,<2.0.0", "filetype>=1.2.0,<2", "eval-type-backport>=0.2.0,<0.3 ; python_version < '3.10'", "banks>=2.2.0,<3", diff --git a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py index 7f814535a3..65516e74cd 100644 --- a/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py +++ b/llama-index-integrations/storage/chat_store/llama-index-storage-chat-store-postgres/llama_index/storage/chat_store/postgres/base.py @@ -18,6 +18,20 @@ from llama_index.core.bridge.pydantic import Field, PrivateAttr from llama_index.core.storage.chat_store.base import BaseChatStore +import json + + +def safe_model_dump_json(model): + """ + Safely dumps a Pydantic model to JSON, even if it contains + non-serializable objects like Google FunctionCall. + """ + try: + return model.model_dump_json(exclude_none=True) + except Exception: + data = model.model_dump(exclude_none=True) + return json.dumps(data, default=lambda o: getattr(o, "__dict__", str(o))) + def get_data_model( base: type, @@ -192,7 +206,7 @@ def set_messages(self, key: str, messages: list[ChatMessage]) -> None: params = { "key": key, - "value": [message.model_dump_json() for message in messages], + "value": [safe_model_dump_json(message) for message in messages], } # Execute the bulk upsert @@ -214,7 +228,7 @@ async def aset_messages(self, key: str, messages: list[ChatMessage]) -> None: params = { "key": key, - "value": [message.model_dump_json() for message in messages], + "value": [safe_model_dump_json(message) for message in messages], } # Execute the bulk upsert @@ -257,7 +271,7 @@ def add_message(self, key: str, message: ChatMessage) -> None: value = array_cat({self._table_class.__tablename__}.value, :value); """ ) - params = {"key": key, "value": [message.model_dump_json()]} + params = {"key": key, "value": [safe_model_dump_json(message)]} session.execute(stmt, params) session.commit() @@ -273,7 +287,7 @@ async def async_add_message(self, key: str, message: ChatMessage) -> None: value = array_cat({self._table_class.__tablename__}.value, :value); """ ) - params = {"key": key, "value": [message.model_dump_json()]} + params = {"key": key, "value": [safe_model_dump_json(message)]} await session.execute(stmt, params) await session.commit()