fix(middleware): preserve human message metadata (#5823)

* fix(middleware): preserve human message metadata

* test(middleware): cover human message metadata injection
This commit is contained in:
WuWenbo 2026-09-25 14:18:09 +08:00 committed by GitHub
parent 33a423d375
commit cf3afe2bac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 35 additions and 7 deletions

View File

@ -103,11 +103,15 @@ class ThreadDataMiddleware(AgentMiddleware[ThreadDataMiddlewareState]):
last_message = messages[-1] if messages else None
if last_message and isinstance(last_message, HumanMessage):
messages[-1] = HumanMessage(
content=last_message.content,
id=last_message.id,
name=last_message.name or "user-input",
additional_kwargs={**last_message.additional_kwargs, "run_id": context.get("run_id"), "timestamp": datetime.now(UTC).isoformat()},
messages[-1] = last_message.model_copy(
update={
"name": last_message.name or "user-input",
"additional_kwargs": {
**last_message.additional_kwargs,
"run_id": context.get("run_id"),
"timestamp": datetime.now(UTC).isoformat(),
},
},
)
return {

View File

@ -1,4 +1,5 @@
import pytest
from langchain_core.messages import HumanMessage
from langgraph.runtime import Runtime
from deerflow.agents.middlewares.thread_data_middleware import ThreadDataMiddleware
@ -66,8 +67,6 @@ class TestThreadDataMiddleware:
def test_before_agent_handles_none_context_with_trailing_human_message(self, tmp_path, monkeypatch):
# Regression: run_id was read via the unguarded `runtime.context`, so a None context plus a
# trailing HumanMessage raised AttributeError (thread_id still resolves from config.configurable).
from langchain_core.messages import HumanMessage
middleware = ThreadDataMiddleware(base_dir=str(tmp_path), lazy_init=True)
runtime = Runtime(context=None)
monkeypatch.setattr(
@ -80,6 +79,31 @@ class TestThreadDataMiddleware:
assert result is not None
assert runtime.context is None
def test_before_agent_preserves_human_message_response_metadata(self, tmp_path):
middleware = ThreadDataMiddleware(base_dir=str(tmp_path), lazy_init=True)
message = HumanMessage(
content="hello",
id="message-1",
response_metadata={"source": "gateway"},
)
result = middleware.before_agent(
state={"messages": [message]},
runtime=Runtime(
context={
"thread_id": "thread-123",
"run_id": "run-123",
},
),
)
assert result is not None
updated_message = result["messages"][-1]
assert updated_message.response_metadata == {"source": "gateway"}
assert updated_message.name == "user-input"
assert updated_message.additional_kwargs["run_id"] == "run-123"
assert updated_message.additional_kwargs["timestamp"]
def test_before_agent_raises_clear_error_when_thread_id_missing_everywhere(self, tmp_path, monkeypatch):
middleware = ThreadDataMiddleware(base_dir=str(tmp_path), lazy_init=True)
monkeypatch.setattr(