fix(announce): use deterministic idempotency keys to prevent duplicate subagent announces#17150
Merged
gumadeiras merged 4 commits intoopenclaw:mainfrom Feb 15, 2026
Conversation
b992e27 to
41ae6a0
Compare
…e subagent announces
When a subagent completes while the main session is busy, the announce
is queued by the application-level announce queue (subagent-announce-
queue.ts) and drained via sendAnnounce → callGateway({ method: 'agent' }).
However, if the main session is still busy when the drain fires, the
gateway-level message queue also captures this callGateway call, creating
a second copy. Both queues eventually deliver, causing duplicate
announcements.
The root cause is that both sendAnnounce and the direct announce path
use crypto.randomUUID() as the idempotency key, generating a unique key
per call. The gateway's dedup cache (context.dedupe) can never match
because each attempt has a different key.
Replace the random keys with deterministic ones derived from stable
identifiers:
- sendAnnounce: announce:{sessionKey}:{enqueuedAt}
- direct announce: announce:{childSessionKey}:{childRunId}
This allows the gateway dedup cache to recognize the second delivery
attempt as a duplicate and return the cached response instead.
Fixes openclaw#17122
41ae6a0 to
54bba3c
Compare
Member
|
Merged via squash. Thanks @widingmarcus-cyber! |
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(announce): use deterministic idempotency keys to prevent duplicate subagent announces
Fixes #17122
Problem
When a subagent completes while the main session is busy, the completion announcement is delivered twice:
subagent-announce-queue.ts) drains and callssendAnnounce→callGateway({ method: "agent" })callGatewaycallRoot Cause
Both
sendAnnounce(queue drain path) and the direct announce path inrunSubagentAnnounceFlowusecrypto.randomUUID()as the idempotency key:The gateway's dedup cache (
context.dedupe.get(\agent:${idem}`)`) can never detect the duplicate because each delivery attempt has a different key.Fix
Replace random idempotency keys with deterministic ones derived from stable identifiers:
This allows the gateway dedup cache to recognize the second delivery attempt and return the cached response instead of processing it again.
Changed Files
src/agents/subagent-announce.tscrypto.randomUUID()with deterministic keys in bothsendAnnounceand direct announce path; remove unusedcryptoimportTesting
Related
Greptile Summary
Replaced random UUIDs with deterministic idempotency keys derived from stable identifiers to prevent duplicate subagent announcements when both the application-level announce queue and gateway-level message queue deliver the same announcement.
Key changes:
sendAnnounce: uses template with session key and enqueue timestamp instead of random UUIDrunSubagentAnnounceFlow: uses template with child session key and run ID instead of random UUIDThe fix allows the gateway's deduplication cache to properly recognize and reject duplicate delivery attempts by using the same idempotency key for both delivery paths.
Confidence Score: 5/5
sessionKey,enqueuedAt,childRunId) are all stable identifiers that remain constant across duplicate delivery attempts. The change is minimal, well-tested (79 agent tests + 101 cron tests passing), and follows the same pattern used for cron duplicate delivery in fix(cron): prevent duplicate delivery for isolated jobs with announce mode #15739.Last reviewed commit: 8f695c3
(5/5) You can turn off certain types of comments like style here!