mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-14 16:08:41 +00:00
fix(mcp): treat a Human Input Card reply as the current user request (#5426)
McpRoutingMiddleware picked the latest user message with is_real_user_message, which rejects every hide_from_ui message. A Human Input Card reply is hidden but is still the user's current request, so when the routing keyword lived only in the clarification answer the deferred MCP tool was never auto-promoted and the model had to call tool_search by hand. Switch _latest_user_message to is_genuine_user_message, the same predicate summarization_middleware already uses for this reason (#5416). Fixes #5425
This commit is contained in:
parent
0a0d768107
commit
ba998a92ac
@ -11,9 +11,10 @@ from langchain.agents.middleware import AgentMiddleware
|
||||
from langchain_core.messages import HumanMessage
|
||||
from langgraph.runtime import Runtime
|
||||
|
||||
from deerflow.agents.middlewares.message_utils import is_genuine_user_message
|
||||
from deerflow.agents.middlewares.tool_promotion_audit_middleware import record_tool_promotion
|
||||
from deerflow.config.tool_search_config import clamp_auto_promote_top_k
|
||||
from deerflow.utils.messages import get_original_user_content_text, is_real_user_message
|
||||
from deerflow.utils.messages import get_original_user_content_text
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -73,8 +74,14 @@ class McpRoutingMiddleware(AgentMiddleware[AgentState]):
|
||||
|
||||
@staticmethod
|
||||
def _latest_user_message(messages: list[Any]) -> HumanMessage | None:
|
||||
"""Latest user-authored message, including a hidden Human Input Card reply.
|
||||
|
||||
The card reply is hidden from the UI but is still the user's current
|
||||
request, so ``is_genuine_user_message`` — not ``is_real_user_message``,
|
||||
which drops every ``hide_from_ui`` message — decides this.
|
||||
"""
|
||||
for message in reversed(messages):
|
||||
if is_real_user_message(message):
|
||||
if is_genuine_user_message(message):
|
||||
return message
|
||||
return None
|
||||
|
||||
|
||||
@ -99,6 +99,31 @@ def test_matching_uses_latest_real_human_message_only():
|
||||
assert middleware._matched_names({"messages": [HumanMessage(content="metrics", name="summary"), HumanMessage(content="orders", additional_kwargs={"hide_from_ui": True})]}) == []
|
||||
|
||||
|
||||
def test_matching_uses_a_hidden_human_input_card_reply_as_the_latest_message():
|
||||
"""A card reply is hidden from the UI but is still the user's current request."""
|
||||
middleware = McpRoutingMiddleware(
|
||||
{"postgres_query": {"priority": 100, "keywords": ["orders"]}},
|
||||
"hash1",
|
||||
3,
|
||||
)
|
||||
reply = HumanMessage(
|
||||
content='For your clarification "Which dataset?", my answer is: orders',
|
||||
additional_kwargs={
|
||||
"hide_from_ui": True,
|
||||
"human_input_response": {
|
||||
"version": 1,
|
||||
"kind": "human_input_response",
|
||||
"source": "ask_clarification",
|
||||
"request_id": "clarification:call-abc",
|
||||
"response_kind": "text",
|
||||
"value": "orders",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert middleware._matched_names({"messages": [HumanMessage(content="no match now"), reply]}) == ["postgres_query"]
|
||||
|
||||
|
||||
def test_matching_supports_casefold_chinese_priority_tiebreak_and_top_k():
|
||||
middleware = McpRoutingMiddleware(
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user