deerflow2/backend/packages/harness/deerflow/agents/middlewares
Nan Gao dcc6f1e678
feat(loop-detection): defer warning injection (#2752)
* fix(loop-detection): defer warn injection to wrap_model_call

The warn branch in LoopDetectionMiddleware injected a HumanMessage
into state from after_model. The tools node had not yet produced
ToolMessage responses to the previous AIMessage(tool_calls=...), so
the new HumanMessage landed *between* the assistant's tool_calls and
their responses. OpenAI/Moonshot reject the next request with
"tool_call_ids did not have response messages" because their
validators require tool_calls to be followed immediately by tool
messages.

Detection now runs in after_model as before, but only enqueues the
warning into a per-thread list. Injection happens in wrap_model_call,
where every prior ToolMessage is already present in request.messages.
The warning is appended at the end as HumanMessage(name="loop_warning")
— pairing intact, AIMessage semantics untouched, no SystemMessage
issues for Anthropic.

Closes #2029, addresses #2255 #2293 #2304 #2511.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(channels): remove loop warning display filter

* feat(loop-detection): scope pending warnings by run

* docs(loop-detection): update docs

* test(loop-detection): assert deferred warnings are queued

* fix(loop-detection): cap transient warning state

* docs: update docs

* add async awrap_model_call test coverage

* docs(loop-detection): document transient warnings

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 14:36:07 +08:00
..
__init__.py feat: add create_deerflow_agent SDK entry point (Phase 1) (#1203) 2026-03-29 15:31:18 +08:00
clarification_middleware.py fix(backend): make clarification messages idempotent (#2350) (#2351) 2026-04-19 22:00:58 +08:00
dangling_tool_call_middleware.py fix(middleware): normalize tool result adjacency before model calls (#2939) 2026-05-15 22:09:04 +08:00
deferred_tool_filter_middleware.py fix: gate deferred MCP tool execution (#2513) 2026-04-24 22:45:41 +08:00
dynamic_context_middleware.py fix(lint): remove duplicate is_dynamic_context_reminder definition (#2837) 2026-05-09 23:40:46 +08:00
llm_error_handling_middleware.py refactor: thread app_config through middleware factories (#2652) 2026-04-30 12:41:09 +08:00
loop_detection_middleware.py feat(loop-detection): defer warning injection (#2752) 2026-05-21 14:36:07 +08:00
memory_middleware.py refactor: thread app_config through lead and subagent task path (#2666) 2026-05-02 06:37:49 +08:00
sandbox_audit_middleware.py feat(sandbox): strengthen bash command auditing with compound splitting and expanded patterns (#1881) 2026-04-07 17:15:24 +08:00
subagent_limit_middleware.py fix(middleware): sync raw tool call metadata (#2757) 2026-05-08 10:08:53 +08:00
summarization_middleware.py fix(harness): preserve dynamic context across summarization (#2823) 2026-05-09 19:39:36 +08:00
thread_data_middleware.py feat: enhance chat history loading with new hooks and UI components (#2338) 2026-04-26 11:20:17 +08:00
title_middleware.py fix title generation with dynamic context reminder (#2830) 2026-05-09 18:22:58 +08:00
todo_middleware.py fix(middleware): Prevent todo completion reminder IMMessage leak (#2907) 2026-05-15 22:12:37 +08:00
token_usage_middleware.py feat: stream subagent token usage to header via terminal task events (#2882) 2026-05-13 23:52:19 +08:00
tool_call_metadata.py fix(middleware): sync raw tool call metadata (#2757) 2026-05-08 10:08:53 +08:00
tool_error_handling_middleware.py fix(subagents): use model override for tools and middleware (#2641) 2026-05-01 22:21:10 +08:00
uploads_middleware.py feat: enhance chat history loading with new hooks and UI components (#2338) 2026-04-26 11:20:17 +08:00
view_image_middleware.py fix(backend): preserve viewed image reducer metadata (#1900) 2026-04-06 16:47:19 +08:00