diff --git a/backend/packages/harness/deerflow/agents/middlewares/loop_detection_middleware.py b/backend/packages/harness/deerflow/agents/middlewares/loop_detection_middleware.py index f96373e..0ae892a 100644 --- a/backend/packages/harness/deerflow/agents/middlewares/loop_detection_middleware.py +++ b/backend/packages/harness/deerflow/agents/middlewares/loop_detection_middleware.py @@ -21,7 +21,7 @@ from typing import override from langchain.agents import AgentState from langchain.agents.middleware import AgentMiddleware -from langchain_core.messages import SystemMessage +from langchain_core.messages import HumanMessage from langgraph.runtime import Runtime logger = logging.getLogger(__name__) @@ -203,8 +203,13 @@ class LoopDetectionMiddleware(AgentMiddleware[AgentState]): return {"messages": [stripped_msg]} if warning: - # Inject a system message warning the model - return {"messages": [SystemMessage(content=warning)]} + # Inject as HumanMessage instead of SystemMessage to avoid + # 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 diff --git a/backend/tests/test_loop_detection_middleware.py b/backend/tests/test_loop_detection_middleware.py index b9aa2da..3bd0c36 100644 --- a/backend/tests/test_loop_detection_middleware.py +++ b/backend/tests/test_loop_detection_middleware.py @@ -2,7 +2,7 @@ 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 ( _HARD_STOP_MSG, @@ -81,7 +81,7 @@ class TestLoopDetection: assert result is not None msgs = result["messages"] assert len(msgs) == 1 - assert isinstance(msgs[0], SystemMessage) + assert isinstance(msgs[0], HumanMessage) assert "LOOP DETECTED" in msgs[0].content def test_warn_only_injected_once(self):