* pr-no_reply: suppress NO_REPLY marker responses
Add Mode-aware NO_REPLY handling on top of PR 655 display.Mode enum.
Agent can return a response beginning with 'NO_REPLY' to silently
skip platform delivery while preserving history + context.
- isSilentReply / couldBeSilentPrefix helpers (regex + prefix test)
- EventText: hold streaming preview while segment could still resolve
to a bare NO_REPLY marker; release (flush) once disambiguated
- silentHold reset at each segment boundary (thinking/tool/user)
- EventResult: detect isSilent on cleaned response; gate context
indicator, reply footer, TTS, and final send; call sp.discard()
to remove preview + skip done reaction via needsDoneReaction gate
* pr-no_reply: document NO_REPLY in injected system prompt
Agents cannot use the silent-reply feature unless they know about it.
Add a 'Silent reply' section to AgentSystemPrompt() describing when and
how to return the bare NO_REPLY marker.
* pr-no_reply: strip trailing NO_REPLY from mixed reasoning+marker responses
Extends NO_REPLY handling to match OpenClaw's stripSilentToken semantics.
Motivation: agents running cron/analysis tasks often narrate their
reasoning before appending NO_REPLY, defeating the bare-only detector.
- stripTrailingSilent helper (regex (?:^|\s+|\*+)NO_REPLY\s*$)
- EventResult: after bare-match check, try trailing strip;
empty result -> fully silent, non-empty -> deliver stripped text
- System prompt clarified: agent may end reply with NO_REPLY line;
stripped reasoning still delivers as normal reply
* test(core): add table-driven tests for NO_REPLY helpers
Cover isSilentReply, stripTrailingSilent, and couldBeSilentPrefix with
table-driven cases locking the contract these helpers expose to the
streaming preview and final-turn paths. Mirrors the coverage approach
used by PR #684 for its simpler strip helper.
isSilentReply: exact bare-marker match is case-insensitive and tolerates
surrounding whitespace/newlines; mixed content or tokens sharing the
prefix are rejected.
stripTrailingSilent: strips a trailing NO_REPLY preceded by whitespace
or markdown asterisks; leaves unchanged when the marker is absent,
mid-string, or glued to a longer token.
couldBeSilentPrefix: true while the trimmed input is a case-insensitive
prefix of NO_REPLY (including empty/whitespace-only), false once it
diverges or grows longer than the marker.
---------
Co-authored-by: Cigarrr <cigarrr@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>