fix(store): add value serialization for LangChain message objects (#128)#129
fix(store): add value serialization for LangChain message objects (#128)#129
Conversation
bsbodden
commented
Dec 11, 2025
- Add value serialization to RedisStore and AsyncRedisStore for handling LangChain message objects
- Reuse existing JsonPlusRedisSerializer from checkpoint package for consistency
- Add comprehensive test coverage for message serialization scenarios
RedisStore was passing values directly to redisvl.SearchIndex.load() which uses standard json.dumps() internally. This caused failures when storing values containing LangChain message objects (HumanMessage, AIMessage, etc.). Changes: - Add _serialize_value() method to BaseRedisStore that uses JsonPlusRedisSerializer - Add _deserialize_value() method for proper revival of complex objects - Update _row_to_item() and _row_to_search_item() to accept deserialize function - Update all call sites in RedisStore and AsyncRedisStore The serialization is smart: simple JSON-serializable values are stored as-is for backward compatibility, while complex objects get the serde wrapper. Closes #128
Add comprehensive test suite for issue #128 covering: - Single HumanMessage storage and retrieval - Multiple message types (SystemMessage, HumanMessage, AIMessage) - Messages with additional kwargs (name, id, additional_kwargs) - Nested message structures in complex data - AIMessage with tool_calls - Search operations with message values
There was a problem hiding this comment.
Pull request overview
This pull request fixes a serialization issue where storing LangChain message objects (HumanMessage, AIMessage, etc.) in RedisStore failed because the underlying redisvl library couldn't serialize them with standard JSON. The fix reuses the existing JsonPlusRedisSerializer from the checkpoint package to handle complex object serialization transparently while maintaining backward compatibility with existing plain JSON values.
Key changes:
- Added automatic value serialization/deserialization for non-JSON-serializable objects using JsonPlusRedisSerializer
- Values are checked for JSON serializability and only wrapped in the serde format when necessary
- Updated both sync and async store implementations to apply deserialization when retrieving values
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 11 comments.
| File | Description |
|---|---|
| tests/test_issue_128_store_message_serialization.py | Comprehensive test suite covering message serialization scenarios including multiple message types, nested structures, tool calls, and search operations (sync only) |
| langgraph/store/redis/base.py | Core serialization logic added to BaseRedisStore with _serialize_value and _deserialize_value methods, plus JsonPlusRedisSerializer initialization and updates to helper functions to accept deserialization callbacks |
| langgraph/store/redis/aio.py | Updated async batch operations to pass deserialize_fn to _row_to_item and _row_to_search_item helper functions |
| langgraph/store/redis/init.py | Updated sync batch operations to pass deserialize_fn to _row_to_item and _row_to_search_item helper functions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Improvements based on PR #129 review: - Move json import to top of file for consistency - Add exact key check (set equality) to prevent collisions with user data that might contain __serde_type__ and __serde_data__ keys - Add comprehensive error handling for deserialization failures with logging - Add hex validation for non-json type deserialization - Fix async store to also apply value serialization in _prepare_batch_PUT_queries_async - Make type handling explicit in serialization (json vs bytes/msgpack) New tests added: - Backward compatibility test for plain JSON values (filters continue to work) - Serde key collision prevention test - Bytes value serialization test - Full async store test suite mirroring sync tests
abrookins
left a comment
There was a problem hiding this comment.
Looks good. Only concern is that if we add the ability for users to specify a custom filter schema, we should more visibly warn them if they then give us data we can't serialize (and thus won't be filterable). But we can should that later, if we add such filtering.