Skip to content

fix(imessage): stop reasoning echo feedback loops and harden reply suppression#25923

Merged
steipete merged 1 commit intomainfrom
fix/imessage-reasoning-loop-25897
Feb 25, 2026
Merged

fix(imessage): stop reasoning echo feedback loops and harden reply suppression#25923
steipete merged 1 commit intomainfrom
fix/imessage-reasoning-loop-25897

Conversation

@steipete
Copy link
Contributor

@steipete steipete commented Feb 25, 2026

Summary

Why this is the right fix

  • addresses both sides of the runaway loop: outbound leakage + inbound re-ingestion
  • uses defense-in-depth at shared outbound boundaries, not channel-specific hotfixes
  • keeps iMessage dedupe robust under delayed polling by preferring provider IDs when available

Tests

  • added iMessage echo-cache unit tests (text normalization, ID matching, ID TTL > text TTL)
  • added inbound iMessage echo-by-messageId regression test
  • added reasoning-suppression tests for outbound normalization and route delivery
  • added message.target extraction regression test

Validation

  • pnpm check ❌ (fails on pre-existing unrelated tsgo errors in extensions/matrix/src/matrix/send-queue.test.ts and src/auto-reply/reply/followup-runner.test.ts)
  • pnpm build
  • pnpm test ❌ (single unrelated failure in src/process/exec.test.ts: no-output timer SIGKILL assertion)

Closes #25897
Closes #25383
Supersedes #25623
Supersedes #25757

Greptile Summary

This PR fixes iMessage reasoning echo feedback loops through a defense-in-depth approach that addresses both sides of the runaway loop: outbound reasoning leakage and inbound echo re-ingestion.

  • iMessage echo cache hardened: SentMessageCache split into dual maps with separate TTLs — messageId lookups use a 60s TTL (vs 5s for text) to handle delayed polling. Text normalization (CRLF, whitespace) and placeholder ID filtering ("ok"/"unknown") improve matching accuracy.
  • Reasoning suppression at shared outbound boundaries: normalizeReplyPayloadsForDelivery and routeReply both filter isReasoning payloads early, preventing hidden thinking text from reaching any channel.
  • message.target fallback for send suppression: extractMessagingToolSend now accepts args.target as an alias for args.to, fixing message-send suppression extraction (same core fix as fix(agents): support message.target in send extraction #25623/fix(message): include target in reply suppression tracking #25757).
  • Comprehensive tests added: Echo cache unit tests (text normalization, ID matching, TTL behavior), inbound echo-by-messageId regression test, reasoning suppression tests for both outbound paths, and message.target extraction test.

Confidence Score: 5/5

  • This PR is safe to merge — changes are well-scoped defensive fixes with comprehensive test coverage at each layer.
  • All changes are additive guards (early returns for isReasoning, upgraded cache with backward-compatible interfaces). The dual-TTL echo cache is a clean improvement over the previous single-map approach. Reasoning suppression is placed at shared outbound boundaries rather than channel-specific hotfixes. Tests cover key scenarios including TTL behavior, normalization, and regression cases. No breaking changes to public APIs.
  • No files require special attention

Last reviewed commit: 90256e9

@openclaw-barnacle openclaw-barnacle bot added channel: imessage Channel integration: imessage agents Agent runtime and tooling size: M maintainer Maintainer-authored PR labels Feb 25, 2026
@cursor
Copy link

cursor bot commented Feb 25, 2026

PR Summary

Medium Risk
Touches shared outbound normalization and iMessage message de-dupe logic; mistakes could suppress legitimate messages or fail to stop echo loops, but changes are well-covered by new tests.

Overview
Prevents hidden reasoning content from being delivered to users by dropping payload.isReasoning at shared outbound boundaries (normalizeReplyPayloadsForDelivery) and in routeReply, with new regression tests.

Hardens iMessage echo suppression by expanding the sent-message cache from text-only to text + outbound messageId matching, normalizing text keys, ignoring placeholder IDs, and using a longer TTL for ID-based dedupe; inbound processing now checks both text and message id and logs the id when present, with new unit tests.

Improves messaging tool-send extraction by accepting target as an alias for to when parsing message send actions.

Written by Cursor Bugbot for commit 90256e9. This will update automatically on new commits. Configure here.

@steipete steipete force-pushed the fix/imessage-reasoning-loop-25897 branch from a071207 to 90256e9 Compare February 25, 2026 00:46
@steipete steipete merged commit 2a11c09 into main Feb 25, 2026
3 checks passed
@steipete steipete deleted the fix/imessage-reasoning-loop-25897 branch February 25, 2026 00:46
@steipete
Copy link
Contributor Author

Landed via temp rebase onto main.

  • Gate: pnpm check; pnpm test src/imessage/monitor/deliver.test.ts src/imessage/monitor/provider.group-policy.test.ts src/imessage/monitor/monitor-provider.echo-cache.test.ts src/imessage/monitor/inbound-processing.test.ts src/infra/outbound/outbound.test.ts src/auto-reply/reply/route-reply.test.ts src/agents/pi-embedded-subscribe.tools.extract.test.ts -- --runInBand
  • Land commit: 90256e9
  • Merge commit: 2a11c09

Thanks @steipete!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: imessage Channel integration: imessage maintainer Maintainer-authored PR size: M

Projects

None yet

1 participant