deerflow2/backend/packages/harness/deerflow/agents
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
..
lead_agent feat: static system prompt with DynamicContextMiddleware for prefix-cache optimization (#2801) 2026-05-09 09:27:02 +08:00
memory fix(trace):memory 中文 in trace info is unicode escape sequence. (#3104) 2026-05-20 22:34:10 +08:00
middlewares feat(loop-detection): defer warning injection (#2752) 2026-05-21 14:36:07 +08:00
__init__.py feat(persistence):Unified persistence layer with event store, feedback, and rebase cleanup (#2134) 2026-04-26 11:09:55 +08:00
factory.py feat(loop-detection): make loop detection configurable with per-tool frequency overrides (#2711) 2026-05-07 16:15:15 +08:00
features.py feat(loop-detection): make loop detection configurable with per-tool frequency overrides (#2711) 2026-05-07 16:15:15 +08:00
thread_state.py refactor: split backend into harness (deerflow.*) and app (app.*) (#1131) 2026-03-14 22:55:52 +08:00