mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-20 22:52:29 +02:00
## Problem
`_messages_delta_reducer` assumed writes always contain pre-typed
`BaseMessage` objects (as noted in its docstring). In practice,
HTTP-driven graphs always receive message input as JSON dicts — the same
way `add_messages` receives them. Using
`DeltaChannel(_messages_delta_reducer)` with any HTTP input would crash
with:
```
AttributeError: 'dict' object has no attribute 'id'
```
This makes `_messages_delta_reducer` unusable for the primary motivating
use-case (replacing `add_messages` in production LLM graphs).
## Fix
Mirror the coercion contract of `add_messages`:
- Regular message dicts (`{"role": "human", "content": "..."}`) →
`convert_to_messages`
- `RemoveMessage` dicts (`{"type": "remove", "id": "..."}`) →
`RemoveMessage` directly (langchain_core's `convert_to_messages` doesn't
support this format)
- `BaseMessage` objects → pass through unchanged
- Lists/sequences → element-wise coercion of the above
The fix is a small `_coerce_one` + `_to_msgs` helper pair that replaces
the previous `[w] if isinstance(w, BaseMessage) else w` generator.
## Tests
Added `test_delta_channel_dict_coercion` in `test_channels.py` covering:
- dict append via `{"role": "human", "content": ..., "id": ...}`
- dict update-in-place (same ID)
- `{"type": "remove", "id": ...}` tombstoning
All 23 existing delta-channel tests still pass.
Release Notes: None
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>