Skip to content

bug: Empty response when agent performs tool-only turn (memory update swallows reply) #84

@alexeymorozua

Description

@alexeymorozua

Description

When a memory hook fires (MAINMEMORY_REMINDER every 6 messages, MEMORY_REFLECTION every 10 messages) and the agent performs only tool calls (e.g., writing to MAINMEMORY.md) without generating text output, the user receives no response at all in Telegram.

Root Cause

The chain of failure:

  1. Hook text (hooks.py:89-100) instructs the agent to update memory "silently" — the agent complies by performing file writes without generating text.

  2. _finish_normal() (flows.py:477) passes response.result (empty string) through without any empty-check:

    text = response.result  # can be ""
  3. send_rich() (sender.py:200) silently skips sending when text is empty:

    if clean_text:  # empty string → falsy → nothing sent
        last_msg = await _send_text_chunks(...)
  4. In streaming mode: editor.has_content is False (no text deltas were streamed), result.text is empty → send_rich() is called with empty text → same silent skip.

Result: The user's message is consumed, the agent does internal work, but zero messages are delivered to the user.

Reproduction

  1. Chat with any agent that has memory hooks enabled
  2. Send exactly the 6th message in a session (triggers MAINMEMORY_REMINDER)
  3. If the agent decides the main action is memory update (and generates no text), the user gets no reply

More frequent with agents doing active knowledge work (many new facts to store).

Suggested Fix

Option A (code-level, recommended): In _finish_normal(), if response.result is empty/whitespace after a successful (non-error, non-abort) turn, inject a minimal fallback text (e.g., "✓" or a configurable acknowledgment).

Option B (hook-level, complementary): Remove the word "silently" from MAINMEMORY_REMINDER and MEMORY_REFLECTION hooks, and add explicit instruction: "Always include a text response to the user, even if it's brief."

Option C (sender-level): In send_rich(), log a warning when clean_text is empty so the issue is at least visible in logs.

Options A + B together would be the most robust fix.

Environment

  • Ductor v0.15.0
  • Multiple agents affected (confirmed on Sonic, likely all agents with memory hooks)
  • Both Mac Mini and Spark (CHUWI) deployments

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions