JasonH 82cf57a9c3
fix(utils): return empty text for content-less messages (#5563)
* fix(utils): return empty text for content-less messages

message_content_to_text fell through to str(content), so a message whose
content is None yielded the truthy literal "None". Two call sites already
work around it with a local `or ""` and name the helper in the comment; the
subagent executor's `text if text else "No response generated"` fallback and
the archive's `if not text: continue` skip cannot work around it, so a
content-less terminal turn was reported as an answer of "None" and a
content-less LLM error fallback surfaced "None" instead of its error_detail.

* test(utils): cover non-None content compatibility and document fallbacks

* test(utils): cover contentless task history and refresh guard comments

---------

Co-authored-by: Lengshuang <90967079+Lesereingrape@users.noreply.github.com>
Co-authored-by: JasonH <4430962+yang0228@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-09-19 10:56:21 +08:00

1.6 KiB

Message Text Extraction

message_content_to_text takes raw message content and treats None as empty text so downstream empty-result, error-detail, and archive-skip fallbacks work. Keep its other conversions unchanged, including newline-separated list blocks and literal strings such as "None". Do not replace it with message_to_text, which takes a whole message and uses different list/mapping semantics. Regression coverage lives in tests/test_utils_messages.py, tests/test_subagent_executor.py, and tests/test_task_continuity.py.

Agent / Tool Assembly Off-Load

Tool and agent assembly re-enters get_available_tools() and may block on MCP discovery, so the four async assembly entry points — run_agent's agent_factory call, task_tool, durable batch _execute_item, and abuild_checkpoint_state_accessor — dispatch through deerflow.utils.assembly_io.run_assembly, a dedicated ContextVar-preserving bounded executor (DEER_FLOW_ASSEMBLY_WORKERS, default 8) rather than the loop's default executor; a hung MCP server therefore parks an assembly worker instead of queueing unrelated default-executor work, and the pool logs a warning when pending assemblies exceed the worker count. tests/blocking_io/test_tool_assembly_offloop.py pins all four offloads plus the ContextVar propagation.

Uploaded Document Summaries

file_outline.py reads outlines and fallback previews as utf-8-sig so an optional leading UTF-8 BOM cannot hide a first-line heading or code fence, or occupy a preview line. Preserve physical line numbers, embedded U+FEFF characters, and the original file bytes.