Message_to_events Drops AIMessage.Additional_kwargs During Replay
When converting a finalized AIMessage into the v3 protocol event stream using message_to_events(), the generated message-finish event does not include the AIMessage.additional_kwargs field. This causes provider-specific data to be lost during cache replay, making replayed execution inconsistent with the original live streaming path.
In langchain_core.language_models._compat_bridge.message_to_events(), the message-finish event is constructed without copying the additional_kwargs attribute from the AIMessage. The live streaming path preserves this attribute, but the replay path omits it by design oversight.
```python
from langchain_core.language_models._compat_bridge import message_to_events
from langchain_core.messages import AIMessage
msg = AIMessage(
content="hello",
additional_kwargs={"provider_state": {"important": "preserve-me"}},
)
events = list(message_to_events(msg))
finish_event = next(event for event in events if event.get("event") == "message-finish")
print("Original:", msg.additional_kwargs)
print("Replayed:", finish_event.get("additional_kwargs"))
assert finish_event.get("additional_kwargs") == msg.additional_kwargs
```
Fixing Code Block
from langchain_core.language_models._compat_bridge import message_to_events as _orig_message_to_events
from langchain_core.messages import AIMessage
def patched_message_to_events(message):
for event in _orig_message_to_events(message):
if event.get("event") == "message-finish" and isinstance(message, AIMessage):
event = dict(event)
event["additional_kwargs"] = message.additional_kwargs
yield event
import langchain_core.language_models._compat_bridge as compat_bridge
compat_bridge.message_to_events = patched_message_to_events
The patch wraps the original message_to_events generator and intercepts the message-finish event. When the source message is an AIMessage, it adds the additional_kwargs field to that event, preserving the data. This approach avoids modifying the rest of the event generation logic and is safe for non-AIMessage types.
Edge Case Audit
Adding an extra key to the message-finish event may break strict event schema validators or downstream consumers that assume a fixed set of keys. In concurrent applications, monkey-patching the module-level function affects all threads and tasks, potentially causing unexpected behavior. Rollback is straightforward: remove the monkey-patch and restore the original function. A permanent fix should be made upstream and accompanied by regression tests.