deerflow2/backend/packages/harness/deerflow/agents/middlewares
Huixin615 88e36d9686
fix(#3189): prevent write_file streaming timeout on long reports (#3195)
* fix(#3189): prevent write_file streaming timeout on long reports

Adds a layered defense against StreamChunkTimeoutError caused by oversized
single-shot write_file tool calls:

- factory: default stream_chunk_timeout to 240s for OpenAI-compatible
  clients (overridable via ModelConfig.stream_chunk_timeout in config.yaml)
- sandbox/tools: server-side 80 KB length guard on non-append write_file
  calls (configurable via DEERFLOW_WRITE_FILE_MAX_BYTES env var, 0 disables);
  rejects oversized payloads with a structured error pointing the model at
  str_replace or append=True
- middleware: classify StreamChunkTimeoutError as transient but cap retries
  at 1 via per-exception _RETRY_BUDGET_OVERRIDES (same-payload retry on a
  chunk-gap timeout buffers the same way upstream; full 3-attempt loop
  would stack 6-12 min of dead air)
- middleware: surface an actionable user-facing message for stream-drop
  exceptions instead of leaking the raw langchain stack
- prompts: add a routing-style File Editing Workflow hint to both lead_agent
  and general_purpose subagent prompts, pointing the model at str_replace
  for incremental edits (mirrors Claude Code's Edit / Codex's apply_patch)
- tests: behavioural coverage for size guard, retry budget override,
  stream-drop user message, factory default injection

Refs #3189

* fix(#3189): drop stream_chunk_timeout for non-OpenAI providers

Address CR feedback on PR #3195:

- factory: pop `stream_chunk_timeout` from kwargs for any model_use_path other than `langchain_openai:ChatOpenAI` instead of returning early. `ModelConfig.stream_chunk_timeout` is part of the shared schema, so a user-supplied value on a non-OpenAI provider would otherwise be forwarded to its constructor and raise `TypeError: unexpected keyword argument`.

- factory: rewrite docstring to describe the actual `exclude_none=True` behaviour (explicit null is excluded and falls back to the default) instead of the misleading "None falling out via exclude_none=True keeps its value".

- tests: add regression coverage asserting the kwarg is stripped before reaching a non-OpenAI provider's constructor.

Refs: bytedance#3189

* fix(#3189): restrict stream-drop user copy to StreamChunkTimeoutError only

Per CR on #3195: narrow _STREAM_DROP_EXCEPTIONS to StreamChunkTimeoutError. Generic httpx RemoteProtocolError / ReadError fall back to the standard 'temporarily unavailable' copy, since they routinely fire on transient network blips where the 'split the output' guidance is misleading. Retry/backoff classification is unchanged — both remain transient/retriable. Tests updated to reflect new copy, plus a symmetric regression test for ReadError.

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-06-07 17:47:11 +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(runtime): guide malformed write_file recovery (#3040) 2026-05-29 17:46:24 +08:00
deferred_tool_filter_middleware.py fix(tool-search): reliably hide deferred MCP schemas by removing the ContextVar (closures + graph state) (#3342) 2026-06-02 22:43:22 +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 fix(#3189): prevent write_file streaming timeout on long reports (#3195) 2026-06-07 17:47:11 +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
safety_finish_reason_middleware.py fix(runtime): suppress tool execution when provider safety-terminates with tool_calls (#3035) 2026-05-22 21:20:28 +08:00
safety_termination_detectors.py fix(runtime): suppress tool execution when provider safety-terminates with tool_calls (#3035) 2026-05-22 21:20:28 +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(tracing): propagate session_id and user_id into Langfuse traces (#2944) 2026-05-21 16:49:31 +08:00
todo_middleware.py fix(todo): reuse thread state schema (#3206) 2026-05-26 23:58:08 +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 feat(agent): add ToolOutputBudgetMiddleware for oversized tool output protection (#3303) 2026-05-29 22:59:26 +08:00
tool_output_budget_middleware.py feat(agent): add ToolOutputBudgetMiddleware for oversized tool output protection (#3303) 2026-05-29 22:59:26 +08:00
uploads_middleware.py fix(agents): offload UploadsMiddleware uploads scan off the event loop (#3311) 2026-05-30 21:46:35 +08:00
view_image_middleware.py fix(backend): preserve viewed image reducer metadata (#1900) 2026-04-06 16:47:19 +08:00