Files
cc-connect/core
ee81bb59e6 feat(core): suppress agent replies marked with NO_REPLY (#682)
* 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>
2026-04-24 06:25:32 +08:00
..