mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-19 04:14:46 +08:00
fix(middleware): use HumanMessage in LoopDetectionMiddleware for Anthropic compat (#1300)
LoopDetectionMiddleware injected SystemMessage mid-conversation to warn about repetitive tool calls. This crashes Anthropic models because langchain_anthropic's _format_messages() requires system messages to appear only at the start of the conversation — interleaved system messages raise 'Received multiple non-consecutive system messages'. Switch the warning injection from SystemMessage to HumanMessage, which works with all providers (Anthropic, OpenAI, Google, etc.). Fixes #1299 Co-authored-by: voidborne-d <voidborne-d@users.noreply.github.com>
This commit is contained in:
@@ -21,7 +21,7 @@ from typing import override
|
|||||||
|
|
||||||
from langchain.agents import AgentState
|
from langchain.agents import AgentState
|
||||||
from langchain.agents.middleware import AgentMiddleware
|
from langchain.agents.middleware import AgentMiddleware
|
||||||
from langchain_core.messages import SystemMessage
|
from langchain_core.messages import HumanMessage
|
||||||
from langgraph.runtime import Runtime
|
from langgraph.runtime import Runtime
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -203,8 +203,13 @@ class LoopDetectionMiddleware(AgentMiddleware[AgentState]):
|
|||||||
return {"messages": [stripped_msg]}
|
return {"messages": [stripped_msg]}
|
||||||
|
|
||||||
if warning:
|
if warning:
|
||||||
# Inject a system message warning the model
|
# Inject as HumanMessage instead of SystemMessage to avoid
|
||||||
return {"messages": [SystemMessage(content=warning)]}
|
# Anthropic's "multiple non-consecutive system messages" error.
|
||||||
|
# Anthropic models require system messages only at the start of
|
||||||
|
# the conversation; injecting one mid-conversation crashes
|
||||||
|
# langchain_anthropic's _format_messages(). HumanMessage works
|
||||||
|
# with all providers. See #1299.
|
||||||
|
return {"messages": [HumanMessage(content=warning)]}
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from langchain_core.messages import AIMessage, SystemMessage
|
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
|
||||||
|
|
||||||
from deerflow.agents.middlewares.loop_detection_middleware import (
|
from deerflow.agents.middlewares.loop_detection_middleware import (
|
||||||
_HARD_STOP_MSG,
|
_HARD_STOP_MSG,
|
||||||
@@ -81,7 +81,7 @@ class TestLoopDetection:
|
|||||||
assert result is not None
|
assert result is not None
|
||||||
msgs = result["messages"]
|
msgs = result["messages"]
|
||||||
assert len(msgs) == 1
|
assert len(msgs) == 1
|
||||||
assert isinstance(msgs[0], SystemMessage)
|
assert isinstance(msgs[0], HumanMessage)
|
||||||
assert "LOOP DETECTED" in msgs[0].content
|
assert "LOOP DETECTED" in msgs[0].content
|
||||||
|
|
||||||
def test_warn_only_injected_once(self):
|
def test_warn_only_injected_once(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user