-
-
Notifications
You must be signed in to change notification settings - Fork 52.5k
Description
Summary
When a sub-agent spawned via sessions_spawn (mode="run") replies with exactly ANNOUNCE_SKIP, the completion message is still delivered directly to the originating channel (e.g. Slack thread). The isAnnounceSkip check exists in the agent-to-agent (sessions_send) announce path but is missing from the sessions_spawn direct completion delivery path in sendSubagentAnnounceDirectly().
Steps to reproduce
- Trigger the main agent session from a Slack channel (or any external channel)
- Main agent spawns a sub-agent via
sessions_spawnwithmode: "run",cleanup: "delete" - Sub-agent completes its task, sends confirmation via
messagetool, then replies with exactlyANNOUNCE_SKIP - Observe that the originating Slack thread receives:
✅ Subagent main finished\n\nANNOUNCE_SKIP
Expected behavior
No completion message should be delivered to the channel when the sub-agent replies exactly ANNOUNCE_SKIP. The docs state: "If the sub-agent replies exactly ANNOUNCE_SKIP, nothing is posted."
Actual behavior
The channel receives a message like:
✅ Subagent main finished
ANNOUNCE_SKIP
This is built by buildCompletionDeliveryMessage() which wraps the raw findings text with a header. The direct delivery path at sendSubagentAnnounceDirectly() sends this completionMessage without checking isAnnounceSkip(findings).
OpenClaw version
2026.2.23
Operating system
macOS 15.3 (Darwin 25.3.0 arm64)
Install method
npm global (Homebrew)
Logs, screenshots, and evidence
Root cause traced in the minified dist source:
1. `buildCompletionDeliveryMessage()` always builds a header + findings message, even when findings === "ANNOUNCE_SKIP"
2. `sendSubagentAnnounceDirectly()` checks `completionMessage?.trim()` but never calls `isAnnounceSkip()`
3. The `isAnnounceSkip()` guard only exists in the `sessions_send` agent-to-agent path (line ~35375 in pi-embedded)
The a2a announce path correctly checks: `if (announceTarget && announceReply && announceReply.trim() && !isAnnounceSkip(announceReply))`
But the spawn direct delivery path does not.Impact and severity
Affected: Any agent using sessions_spawn sub-agents that reply ANNOUNCE_SKIP, with delivery to Slack/Telegram/Discord channels
Severity: Medium (cosmetic but confusing — internal tokens leak to end users)
Frequency: 100% repro on every sub-agent completion
Consequence: Raw internal tokens ("ANNOUNCE_SKIP", "Subagent main finished") appear as visible messages in user-facing channels, undermining trust and professionalism
Additional information
Suggested fix: In buildCompletionDeliveryMessage(), return empty string when findings.trim() === "ANNOUNCE_SKIP":
function buildCompletionDeliveryMessage(params) {
const findingsText = params.findings.trim();
if (findingsText === "ANNOUNCE_SKIP") return ""; // skip delivery
const hasFindings = findingsText.length > 0 && findingsText !== "(no output)";
// ...
}This causes the existing completionMessage?.trim() guard in sendSubagentAnnounceDirectly() to skip delivery. We applied this as a local monkey-patch and confirmed it resolves the issue.