fix: ignore middleware prompts in run journal input (#3780)

This commit is contained in:
Huixin615 2026-06-27 23:30:14 +08:00 committed by GitHub
parent 3e2f1bbe49
commit e5a610e845
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 3 deletions

View file

@ -197,12 +197,12 @@ class RunJournal(BaseCallbackHandler):
[len(batch) for batch in messages],
)
# Capture the first human message sent to any LLM in this run.
if not self._first_human_msg and messages:
# Capture the first user message sent to the lead agent in this run.
caller = self._identify_caller(tags)
if caller == "lead_agent" and 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" 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(
event_type="llm.human.input",

View file

@ -924,6 +924,57 @@ class TestChatModelStartHumanMessage:
assert len(human_events) == 1
assert human_events[0]["content"]["content"] == "Real question"
@pytest.mark.anyio
async def test_summarization_prompt_does_not_capture_first_human_message(self, journal_setup):
"""Internal summarization prompts must not replace the run's real user input."""
from langchain_core.messages import HumanMessage
j, store = journal_setup
summarization_prompt = HumanMessage(
content="<role>\nContext Extraction Assistant\n</role>\n\n<primary_objective>\nExtract context...",
)
j.on_chat_model_start(
{},
[[summarization_prompt]],
run_id=uuid4(),
tags=["middleware:summarize"],
)
j.on_chat_model_start(
{},
[[HumanMessage(content="Real user follow-up")]],
run_id=uuid4(),
tags=["lead_agent"],
)
await j.flush()
assert j._first_human_msg == "Real user follow-up"
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 user follow-up"
assert human_events[0]["metadata"]["caller"] == "lead_agent"
@pytest.mark.anyio
@pytest.mark.parametrize("tags", [["middleware:summarize"], ["subagent:research"]])
async def test_non_lead_human_prompts_are_not_captured_as_user_input(self, journal_setup, tags):
"""Only lead-agent LLM starts create UI-facing human input events."""
from langchain_core.messages import HumanMessage
j, store = journal_setup
j.on_chat_model_start(
{},
[[HumanMessage(content="Internal prompt")]],
run_id=uuid4(),
tags=tags,
)
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_only_first_human_message_captured(self, journal_setup):
"""Subsequent on_chat_model_start calls do not overwrite the first message."""