mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-07-21 10:15:47 +00:00
fix(runtime): skip hidden human messages in journal (#3698)
Co-authored-by: rayhpeng <rayhpeng@gmail.com>
This commit is contained in:
@@ -225,7 +225,7 @@ class RunJournal(BaseCallbackHandler):
|
||||
if not self._first_human_msg and messages:
|
||||
for batch in reversed(messages):
|
||||
for m in reversed(batch):
|
||||
if isinstance(m, HumanMessage) and m.name != "summary":
|
||||
if isinstance(m, HumanMessage) and m.name != "summary" and m.additional_kwargs.get("hide_from_ui") is not True:
|
||||
caller = self._identify_caller(tags)
|
||||
self.set_first_human_message(m.text)
|
||||
self._put(
|
||||
|
||||
@@ -854,6 +854,76 @@ class TestChatModelStartHumanMessage:
|
||||
|
||||
assert j._first_human_msg == "Real question"
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_skips_hidden_human_messages(self, journal_setup):
|
||||
"""HumanMessages hidden from the UI are internal context, not user input."""
|
||||
from langchain_core.messages import HumanMessage
|
||||
|
||||
j, store = journal_setup
|
||||
messages_batch = [
|
||||
[
|
||||
HumanMessage(content="What is the weather today?"),
|
||||
HumanMessage(
|
||||
content="Your todo list from earlier...",
|
||||
name="todo_reminder",
|
||||
additional_kwargs={"hide_from_ui": True},
|
||||
),
|
||||
],
|
||||
]
|
||||
j.on_chat_model_start({}, messages_batch, run_id=uuid4(), tags=["lead_agent"])
|
||||
await j.flush()
|
||||
|
||||
assert j._first_human_msg == "What is the weather today?"
|
||||
assert j.get_completion_data()["message_count"] == 1
|
||||
events = await store.list_events("t1", "r1")
|
||||
human_events = [e for e in events if e["event_type"] == "llm.human.input"]
|
||||
assert len(human_events) == 1
|
||||
assert human_events[0]["content"]["content"] == "What is the weather today?"
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_only_hidden_human_messages_are_not_captured(self, journal_setup):
|
||||
"""A prompt containing only internal HumanMessages has no user input."""
|
||||
from langchain_core.messages import HumanMessage
|
||||
|
||||
j, store = journal_setup
|
||||
hidden_message = HumanMessage(
|
||||
content="Internal context",
|
||||
additional_kwargs={"hide_from_ui": True},
|
||||
)
|
||||
j.on_chat_model_start({}, [[hidden_message]], run_id=uuid4(), tags=["lead_agent"])
|
||||
await j.flush()
|
||||
|
||||
assert j._first_human_msg is None
|
||||
assert j.get_completion_data()["message_count"] == 0
|
||||
events = await store.list_events("t1", "r1")
|
||||
assert not any(e["event_type"] == "llm.human.input" for e in events)
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_visible_human_message_after_hidden_only_prompt_is_captured(self, journal_setup):
|
||||
"""Skipping an internal-only prompt does not block later user input."""
|
||||
from langchain_core.messages import HumanMessage
|
||||
|
||||
j, store = journal_setup
|
||||
hidden_message = HumanMessage(
|
||||
content="Internal context",
|
||||
additional_kwargs={"hide_from_ui": True},
|
||||
)
|
||||
j.on_chat_model_start({}, [[hidden_message]], run_id=uuid4(), tags=["lead_agent"])
|
||||
j.on_chat_model_start(
|
||||
{},
|
||||
[[HumanMessage(content="Real question")]],
|
||||
run_id=uuid4(),
|
||||
tags=["lead_agent"],
|
||||
)
|
||||
await j.flush()
|
||||
|
||||
assert j._first_human_msg == "Real question"
|
||||
assert j.get_completion_data()["message_count"] == 1
|
||||
events = await store.list_events("t1", "r1")
|
||||
human_events = [e for e in events if e["event_type"] == "llm.human.input"]
|
||||
assert len(human_events) == 1
|
||||
assert human_events[0]["content"]["content"] == "Real question"
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_only_first_human_message_captured(self, journal_setup):
|
||||
"""Subsequent on_chat_model_start calls do not overwrite the first message."""
|
||||
|
||||
Reference in New Issue
Block a user