diff --git a/backend/tests/test_thread_data_middleware.py b/backend/tests/test_thread_data_middleware.py index 4cc289b2d..7336d5c57 100644 --- a/backend/tests/test_thread_data_middleware.py +++ b/backend/tests/test_thread_data_middleware.py @@ -10,10 +10,11 @@ def _as_posix(path: str) -> str: return path.replace("\\", "/") -def _make_context(thread_id: str) -> DeerFlowContext: +def _make_context(thread_id: str, run_id: str | None = None) -> DeerFlowContext: return DeerFlowContext( app_config=AppConfig(sandbox=SandboxConfig(use="test")), thread_id=thread_id, + run_id=run_id, ) @@ -53,3 +54,42 @@ class TestThreadDataMiddleware: with pytest.raises(ValueError, match="Thread ID is required"): middleware.before_agent(state={}, runtime=Runtime(context=_make_context(""))) + + def test_before_agent_stamps_run_id_and_timestamp_on_last_human_message(self, tmp_path): + """Smoke for the release/2.0-rc + PR merge: run_id from typed + DeerFlowContext flows into the trailing HumanMessage's + additional_kwargs alongside an ISO-8601 timestamp.""" + from langchain_core.messages import HumanMessage + from langgraph.runtime import Runtime + + middleware = ThreadDataMiddleware(base_dir=str(tmp_path), lazy_init=True) + original = HumanMessage(content="hello", id="m-1") + + result = middleware.before_agent( + state={"messages": [original]}, + runtime=Runtime(context=_make_context("t-stamp", run_id="r-stamp")), + ) + + assert result is not None + stamped = result["messages"][-1] + assert isinstance(stamped, HumanMessage) + assert stamped.id == "m-1" + assert stamped.name == "user-input" + assert stamped.additional_kwargs["run_id"] == "r-stamp" + assert "timestamp" in stamped.additional_kwargs + + def test_before_agent_stamps_none_run_id_when_context_omits_it(self, tmp_path): + """run_id is optional: middleware must still stamp (with None) rather than crash.""" + from langchain_core.messages import HumanMessage + from langgraph.runtime import Runtime + + middleware = ThreadDataMiddleware(base_dir=str(tmp_path), lazy_init=True) + + result = middleware.before_agent( + state={"messages": [HumanMessage(content="hi", id="m-2")]}, + runtime=Runtime(context=_make_context("t-no-run")), + ) + + assert result is not None + stamped = result["messages"][-1] + assert stamped.additional_kwargs["run_id"] is None