diff --git a/python/packages/core/agent_framework/_threads.py b/python/packages/core/agent_framework/_threads.py index f7603a7c3c..92469a78d5 100644 --- a/python/packages/core/agent_framework/_threads.py +++ b/python/packages/core/agent_framework/_threads.py @@ -140,6 +140,7 @@ def __init__( """ if not messages: self.messages: list[ChatMessage] = [] + return if not isinstance(messages, list): raise TypeError("Messages should be a list") new_messages: list[ChatMessage] = [] diff --git a/python/packages/core/tests/core/test_threads.py b/python/packages/core/tests/core/test_threads.py index 8049501789..492ed11519 100644 --- a/python/packages/core/tests/core/test_threads.py +++ b/python/packages/core/tests/core/test_threads.py @@ -384,6 +384,18 @@ def test_init_empty(self) -> None: assert len(state.messages) == 0 + def test_init_none(self) -> None: + """Test ChatMessageStoreState initialization with None messages.""" + state = ChatMessageStoreState(messages=None) + + assert len(state.messages) == 0 + + def test_init_no_messages_arg(self) -> None: + """Test ChatMessageStoreState initialization without messages argument.""" + state = ChatMessageStoreState() + + assert len(state.messages) == 0 + class TestThreadState: """Test cases for AgentThreadState class.""" @@ -415,3 +427,22 @@ def test_init_defaults(self) -> None: assert state.service_thread_id is None assert state.chat_message_store_state is None + + def test_init_with_chat_message_store_state_no_messages(self) -> None: + """Test AgentThreadState initialization with chat_message_store_state without messages field. + + This tests the scenario where a custom ChatMessageStore (like RedisChatMessageStore) + serializes its state without a 'messages' field, containing only configuration data + like thread_id, redis_url, etc. + """ + store_data: dict[str, Any] = { + "type": "redis_store_state", + "thread_id": "test_thread_123", + "redis_url": "redis://localhost:6379", + "key_prefix": "chat_messages", + } + state = AgentThreadState.from_dict({"chat_message_store_state": store_data}) + + assert state.service_thread_id is None + assert state.chat_message_store_state is not None + assert state.chat_message_store_state.messages == [] diff --git a/python/packages/redis/tests/test_redis_chat_message_store.py b/python/packages/redis/tests/test_redis_chat_message_store.py index e445b09809..fa403eb2fe 100644 --- a/python/packages/redis/tests/test_redis_chat_message_store.py +++ b/python/packages/redis/tests/test_redis_chat_message_store.py @@ -495,3 +495,20 @@ async def test_extend(self, redis_store, mock_redis_client, sample_messages): # Verify rpush was called for each message pipeline_mock = mock_redis_client.pipeline.return_value.__aenter__.return_value assert pipeline_mock.rpush.call_count >= 2 + + async def test_serialize_with_agent_thread(self, redis_store, sample_messages): + """Test that RedisChatMessageStore can be serialized within an AgentThread. + + This test verifies the fix for issue #1991 where calling thread.serialize() + with a RedisChatMessageStore would fail with "Messages should be a list" error. + """ + from agent_framework import AgentThread + + thread = AgentThread(message_store=redis_store) + await thread.on_new_messages(sample_messages) + + serialized = await thread.serialize() + + assert serialized is not None + assert "chat_message_store_state" in serialized + assert serialized["chat_message_store_state"] is not None