Skip to content

fix(agents): suppress ANNOUNCE_SKIP in sessions_spawn direct completion delivery#25822

Closed
widingmarcus-cyber wants to merge 1 commit intoopenclaw:mainfrom
widingmarcus-cyber:fix/spawn-announce-skip-25800
Closed

fix(agents): suppress ANNOUNCE_SKIP in sessions_spawn direct completion delivery#25822
widingmarcus-cyber wants to merge 1 commit intoopenclaw:mainfrom
widingmarcus-cyber:fix/spawn-announce-skip-25800

Conversation

@widingmarcus-cyber
Copy link
Contributor

@widingmarcus-cyber widingmarcus-cyber commented Feb 24, 2026

Problem

When a sub-agent spawned via sessions_spawn replies exactly ANNOUNCE_SKIP, the completion message is still delivered to the originating channel. The user sees:

✅ Subagent main finished

ANNOUNCE_SKIP

The isAnnounceSkip() guard exists in the sessions_send (agent-to-agent) announce path, but is missing from the sessions_spawn direct completion delivery path.

Root Cause

  1. buildCompletionDeliveryMessage() wraps findings text in a header unconditionally, even when findings is ANNOUNCE_SKIP
  2. sendSubagentAnnounceDirectly() checks completionMessage?.trim() but never calls isAnnounceSkip()
  3. runSubagentAnnounceFlow() has no early exit for ANNOUNCE_SKIP replies

Fix

Two-layer defense:

  1. Early exit in runSubagentAnnounceFlow(): When the subagent reply is ANNOUNCE_SKIP, skip the entire announce flow (both direct completion and agent-routed trigger messages). Returns true (handled) so cleanup proceeds normally.

  2. Guard in buildCompletionDeliveryMessage(): Returns empty string when isAnnounceSkip(findings), so the existing completionMessage?.trim() guard in sendSubagentAnnounceDirectly() also skips delivery. This is defense-in-depth for any code path that calls the builder directly.

Tests

3 new tests in subagent-announce.format.test.ts:

  • Suppresses all delivery when subagent replies exactly ANNOUNCE_SKIP (completion mode)
  • Suppresses delivery for ANNOUNCE_SKIP in non-completion mode
  • Handles whitespace-padded ANNOUNCE_SKIP replies

All 46 announce format tests pass. All 18 sessions tool tests pass.

Closes #25800

Greptile Summary

Adds ANNOUNCE_SKIP suppression to the sessions_spawn direct completion delivery path, which was previously missing this guard (the sessions_send agent-to-agent path already had it). The fix uses a two-layer defense: an early exit in runSubagentAnnounceFlow() that skips the entire announce flow when the subagent reply is ANNOUNCE_SKIP, and a guard in buildCompletionDeliveryMessage() that returns an empty string so the existing completionMessage?.trim() check also prevents delivery.

  • Early exit in runSubagentAnnounceFlow() returns true (handled) so cleanup still proceeds via the finally block
  • Defense-in-depth guard in buildCompletionDeliveryMessage() covers any code path that calls the builder directly
  • Reuses the existing isAnnounceSkip() helper from sessions-send-helpers.ts which handles whitespace trimming
  • 3 new tests cover exact match, non-completion mode, and whitespace-padded variants

Confidence Score: 5/5

  • This PR is safe to merge - it adds a well-scoped guard using an existing helper with good test coverage.
  • The change is minimal and well-targeted: two guard checks using an existing, well-tested helper function (isAnnounceSkip). The early return in runSubagentAnnounceFlow correctly returns true (handled) so cleanup proceeds normally via the finally block. The defense-in-depth guard in buildCompletionDeliveryMessage returns empty string which integrates cleanly with existing null/empty checks downstream. Three new tests comprehensively cover the key scenarios. No regressions are introduced to the existing 46 test cases.
  • No files require special attention.

Last reviewed commit: 45985f1

…on delivery

The sessions_send (agent-to-agent) path correctly checks isAnnounceSkip()
before delivering announcements, but the sessions_spawn direct completion
path in runSubagentAnnounceFlow() and buildCompletionDeliveryMessage() had
no such guard. When a sub-agent replied exactly 'ANNOUNCE_SKIP', the token
was wrapped in a completion header ('✅ Subagent main finished\n\nANNOUNCE_SKIP')
and delivered to the originating channel.

Fix:
- Add early return in runSubagentAnnounceFlow() when the subagent reply is
  ANNOUNCE_SKIP, suppressing both direct completion and agent-routed delivery
- Add isAnnounceSkip() guard in buildCompletionDeliveryMessage() as defense
  in depth, returning empty string so the existing completionMessage?.trim()
  guard in sendSubagentAnnounceDirectly() also skips delivery

Tests: 3 new tests covering completion-mode, non-completion-mode, and
whitespace-padded ANNOUNCE_SKIP replies. All 46 announce format tests pass.

Closes openclaw#25800
steipete added a commit that referenced this pull request Feb 24, 2026
#25821 #25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
@steipete
Copy link
Contributor

Landed on main via consolidated reliability fix commit:
53f9b7d

This PR’s ANNOUNCE_SKIP defense-in-depth approach was preserved and extended with:

  • announce flow early-return for ANNOUNCE_SKIP
  • completion builder guard
  • transient direct-delivery retry logic for channel unavailability
  • additional regression tests across direct completion and direct agent announce paths

Thank you for the solid patch and test additions.

@steipete steipete closed this Feb 24, 2026
gavinwxx-vybers added a commit to Vybers-AI/openclaw that referenced this pull request Feb 25, 2026
* ui: block svg data image opens and harden tests

* changelog: credit both chat-image fix contributors

* test(ui): reject base64 SVG data URLs

* changelog: include openclaw#25847 in chat image safety entry (openclaw#25847) (thanks @shakkernerd)

* refactor(ios): drop legacy talk payload and keychain fallbacks

* chore: sync plugin versions to 2026.2.24

* chore: refresh lockfile after plugin devDependency cleanup

* fix(config): soften antigravity removal fallout (openclaw#25538)

Land openclaw#25538 by @chilu18 to keep legacy google-antigravity-auth config entries non-fatal after removal (see openclaw#25862).

Co-authored-by: chilu18 <chilu.machona@icloud.com>

* fix(security): lock sandbox tmp media paths to openclaw roots

* docs(security): document openclaw temp-folder boundary

* fix(security): restrict default safe-bin trusted dirs

* fix: enforce local media root checks for attachment hydration

* fix(synology-chat): fail closed empty allowlist

* docs(changelog): add synology-chat allowlist fail-closed note

* fix: harden routing/session isolation for followups and heartbeat

* feat(sandbox): block container namespace joins by default

* refactor(sandbox): centralize network mode policy helpers

* fix(channels,sandbox): land hard breakage cluster from reviewed PR bases

Lands reviewed fixes based on openclaw#25839 (@pewallin), openclaw#25841 (@joshjhall), and openclaw#25737/@25713 (@DennisGoldfinger/@peteragility), with additional hardening + regression tests for queue cleanup and shell script safety.

Fixes openclaw#25836
Fixes openclaw#25840
Fixes openclaw#25824
Fixes openclaw#25868

Co-authored-by: Peter Wallin <pwallin@gmail.com>
Co-authored-by: Joshua Hall <josh@yaplabs.com>
Co-authored-by: Dennis Goldfinger <dennisgoldfinger@gmail.com>
Co-authored-by: peteragility <peteragility@users.noreply.github.com>

* refactor(synology-chat): centralize DM auth and fail fast startup

* test: add routing/session isolation edge-case regressions

* refactor: centralize followup origin routing helpers

* refactor(outbound): centralize attachment media policy

* refactor: harden safe-bin trusted dir diagnostics

* fix(zalo): enforce group sender policy in groups

* docs: update changelog for safe-bin hardening

* test(line): align tmp-root expectation after sandbox hardening

* fix(web-search): reduce provider auto-detect log noise

* test(matrix,discord,sandbox): expand breakage regression coverage

* refactor(matrix,tests): extract helpers and inject send-queue timing

* refactor(zalo): split monitor access and webhook logic

* Gateway/Security: protect /api/channels plugin root

* fix(telegram): block unauthorized DM media downloads

* Security: sanitize inherited host exec env

* Changelog: add entry for exec env sanitization

* fix(security): classify hook sessions case-insensitively

* refactor(outbound): unify attachment hydration flow

* refactor(telegram): simplify DM media auth precheck flow

* fix(automation): harden announce delivery + cron coding profile (openclaw#25813 openclaw#25821 openclaw#25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>

* security(voice-call): detect Telnyx webhook replay

* Auto-reply: add exact stop trigger for do not do that

* Auto-reply tests: assert exact do not do that behavior

* Gateway tests: cover exact do not do that stop matching

* Telegram tests: route exact do not do that to control lane

* Changelog: note exact do not do that stop trigger

* refactor(tmp): harden temp boundary guardrails

* fix(whatsapp): stop retry loop on non-retryable 440 close

* test(types): fix ts narrowing regressions in followup and matrix queue tests

* fix(onboard): avoid false 'telegram plugin not available' block

* fix: normalize "bedrock" provider ID to "amazon-bedrock"

Add "bedrock" and "aws-bedrock" as aliases for the canonical
"amazon-bedrock" provider ID in normalizeProviderId().

Without this mapping, configuring a model as "bedrock/..." causes
the auth resolution fallback to miss the Bedrock-specific AWS SDK
path, since the fallback check requires normalized === "amazon-bedrock".
This primarily affects the main agent when the explicit auth override
is not preserved through config merging.

Fixes openclaw#15716

* docs(changelog): backfill landed fix PR entries

* fix(security): harden system.run companion command binding

* fix(discord): land proxy/media/reaction/model-picker regressions

Reimplements core Discord fixes from openclaw#25277 openclaw#25523 openclaw#25575 openclaw#25588 openclaw#25731 with expanded tests.

- thread proxy-aware fetch into inbound attachment/sticker downloads
- fetch /gateway/bot via proxy dispatcher before ws connect
- wire statusReactions emojis/timing overrides into controller
- compact model-picker custom_id keys with backward-compatible parsing

Co-authored-by: openperf <openperf@users.noreply.github.com>
Co-authored-by: chilu18 <chilu18@users.noreply.github.com>
Co-authored-by: Yipsh <Yipsh@users.noreply.github.com>
Co-authored-by: lbo728 <lbo728@users.noreply.github.com>
Co-authored-by: s1korrrr <s1korrrr@users.noreply.github.com>

* docs(changelog): add reporter credit for exec companion hardening

* fix(macos): guard voice audio paths with no input device (openclaw#25817)

Co-authored-by: Stefan Förster <103369858+sfo2001@users.noreply.github.com>

* fix(macos): prefer openclaw binary while keeping pnpm fallback (openclaw#25512)

Co-authored-by: Peter Machona <7957943+chilu18@users.noreply.github.com>

* Auth: bypass cooldown tracking for OpenRouter

* Auth: use cooldown helper in explicit profile order

* Tests: cover OpenRouter cooldown display bypass

* Tests: skip OpenRouter failure cooldown persistence

* Tests: keep OpenRouter runnable with legacy cooldown markers

* Tests: preserve OpenRouter explicit auth order under cooldown fields

* Changelog: note OpenRouter cooldown bypass

* Changelog: remove unrelated session entries from PR

* Update CHANGELOG.md

* fix(macos): default voice wake forwarding to webchat (openclaw#25440)

Co-authored-by: Peter Machona <7957943+chilu18@users.noreply.github.com>

* fix(macos): keep Return for IME marked text commit (openclaw#25178)

Co-authored-by: jft0m <9837901+bottotl@users.noreply.github.com>

* fix(security): block env depth-overflow approval bypass

* fix(macos): resolve webchat panel corner clipping (openclaw#22458)

Co-authored-by: apethree <3081182+apethree@users.noreply.github.com>
Co-authored-by: agisilaos <3073709+agisilaos@users.noreply.github.com>

* Agents: trust explicit allowlist refs beyond catalog

* Tests: cover allowlist refs missing from catalog

* Gateway tests: accept allowlisted refs absent from catalog

* Gateway tests: include synthetic allowlist models in models.list

* Changelog: note allowlist stale-catalog model selection fix

* fix(discord): harden voice DAVE receive reliability (openclaw#25861)

Reimplements and consolidates related work:
- openclaw#24339 stale disconnect/destroyed session guards
- openclaw#25312 voice listener cleanup on stop
- openclaw#23036 restore @snazzah/davey runtime dependency

Adds Discord voice DAVE config passthrough, repeated decrypt failure
rejoin recovery, regression tests, docs, and changelog updates.

Co-authored-by: Frank Yang <frank.ekn@gmail.com>
Co-authored-by: Do Cao Hieu <admin@docaohieu.com>

* fix(macos): clean warnings and harden gateway/talk config parsing

* docs(discord): document DAVE defaults and decrypt recovery

* test: bridge discord voice private casts via unknown

* docs(changelog): remove next-release shipping sentence

* refactor(exec): split system.run phases and align ts/swift validator contracts

* fix(windows): skip unreliable dev comparison in fs-safe openVerifiedLocalFile

On Windows, device IDs (dev) returned by handle.stat() and fs.lstat()
may differ even for the same file, causing false-positive 'path-mismatch'
errors when reading local media files.

This fix introduces a statsMatch() helper that:
- Always compares inode (ino) values
- Skips device ID (dev) comparison on Windows where it's unreliable
- Maintains full comparison on Unix platforms

Fixes openclaw#25699

* fix: align windows safe-open file identity checks

* refactor: dedupe exec wrapper denial plan and test setup

* fix: harden iMessage echo dedupe and reasoning suppression (openclaw#25897)

* test(media): add win32 dev=0 local media regression

* refactor: extract iMessage echo cache and unify suppression guards

* test: normalize tmp media path assertion for windows

* fix(render): seed Control UI origin config on first boot

The gateway requires controlUi.allowedOrigins when binding to LAN.
On Render, the persistent disk starts empty with no openclaw.json.
Seed a minimal config with dangerouslyAllowHostHeaderOriginFallback
on first boot (safe behind Render's HTTPS reverse proxy).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(deps): update dependencies except carbon

* fix(agents): normalize SiliconFlow Pro thinking=off payload (openclaw#25435)

Land PR openclaw#25435 from @Zjianru.
Changelog: add 2026.2.24 fix entry with contributor credit.

Co-authored-by: codez <codezhujr@gmail.com>

* fix(telegram): refresh global undici dispatcher for autoSelectFamily (openclaw#25682)

Land PR openclaw#25682 from @lairtonlelis after maintainer rework:
track dispatcher updates when network decision changes to avoid stale global fetch behavior.

Co-authored-by: Ailton <lairton@telnyx.com>

* fix(synology-chat): land @bmendonca3 fail-closed allowlist follow-up (openclaw#25827)

Carry fail-closed empty-allowlist guard clarity and changelog attribution for PR openclaw#25827.

Co-authored-by: Brian Mendonca <brianmendonca@Brians-MacBook-Air.local>

* fix(agents): reduce billing false positives on long text (openclaw#25680)

Land PR openclaw#25680 from @lairtonlelis.
Retain explicit status/code/http 402 detection for oversized structured payloads.

Co-authored-by: Ailton <lairton@telnyx.com>

* fix(render): add docker entrypoint script for config seeding

The inline shell command in render.yaml's dockerCommand wasn't
reliably creating the seed config. Replace with a proper entrypoint
script that creates a minimal openclaw.json with
dangerouslyAllowHostHeaderOriginFallback on first boot, then starts
the gateway bound to LAN on the PORT env var.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(ui): inherit default model fallbacks in agents overview (openclaw#25729)

Land PR openclaw#25729 from @Suko.
Use shared fallback-resolution helper and add regression coverage for default, override, and explicit-empty cases.

Co-authored-by: suko <miha.sukic@gmail.com>

* fix(heartbeat): default target none and internalize relay prompts

* test(windows): normalize risky-path assertions

---------

Co-authored-by: Shakker <shakkerdroid@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: chilu18 <chilu.machona@icloud.com>
Co-authored-by: Peter Wallin <pwallin@gmail.com>
Co-authored-by: Joshua Hall <josh@yaplabs.com>
Co-authored-by: Dennis Goldfinger <dennisgoldfinger@gmail.com>
Co-authored-by: peteragility <peteragility@users.noreply.github.com>
Co-authored-by: Brian Mendonca <brianmendonca@Brians-MacBook-Air.local>
Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: Mark Musson <mark@musson.co.za>
Co-authored-by: suko <miha.sukic@gmail.com>
Co-authored-by: Fred White <fwhite13@users.noreply.github.com>
Co-authored-by: openperf <openperf@users.noreply.github.com>
Co-authored-by: chilu18 <chilu18@users.noreply.github.com>
Co-authored-by: Yipsh <Yipsh@users.noreply.github.com>
Co-authored-by: lbo728 <lbo728@users.noreply.github.com>
Co-authored-by: s1korrrr <s1korrrr@users.noreply.github.com>
Co-authored-by: Stefan Förster <103369858+sfo2001@users.noreply.github.com>
Co-authored-by: Peter Machona <7957943+chilu18@users.noreply.github.com>
Co-authored-by: jft0m <9837901+bottotl@users.noreply.github.com>
Co-authored-by: apethree <3081182+apethree@users.noreply.github.com>
Co-authored-by: agisilaos <3073709+agisilaos@users.noreply.github.com>
Co-authored-by: Frank Yang <frank.ekn@gmail.com>
Co-authored-by: Do Cao Hieu <admin@docaohieu.com>
Co-authored-by: Gavin X. Wang <gavinvybers@Gavins-MacBook-Pro.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: codez <codezhujr@gmail.com>
Co-authored-by: Ailton <lairton@telnyx.com>
joshavant pushed a commit that referenced this pull request Feb 25, 2026
#25821 #25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
margulans pushed a commit to margulans/Neiron-AI-assistant that referenced this pull request Feb 25, 2026
…claw#25813 openclaw#25821 openclaw#25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
Jackson3195 pushed a commit to Jackson3195/openclaw-with-a-personal-touch that referenced this pull request Feb 25, 2026
…claw#25813 openclaw#25821 openclaw#25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
brianleach pushed a commit to brianleach/openclaw that referenced this pull request Feb 26, 2026
…claw#25813 openclaw#25821 openclaw#25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
execute008 pushed a commit to execute008/openclaw that referenced this pull request Feb 27, 2026
…claw#25813 openclaw#25821 openclaw#25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
r4jiv007 pushed a commit to r4jiv007/openclaw that referenced this pull request Feb 28, 2026
…claw#25813 openclaw#25821 openclaw#25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
…claw#25813 openclaw#25821 openclaw#25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
thebenjaminlee pushed a commit to escape-velocity-ventures/openclaw that referenced this pull request Mar 7, 2026
…claw#25813 openclaw#25821 openclaw#25822)

Co-authored-by: Shawn <shenghuikevin@shenghuideMac-mini.local>
Co-authored-by: 不做了睡大觉 <user@example.com>
Co-authored-by: Marcus Widing <widing.marcus@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: sessions_spawn direct completion delivery ignores ANNOUNCE_SKIP

2 participants