Skip to content

perf(imessage): show typing sooner for slow replies#95621

Merged
omarshahine merged 4 commits into
mainfrom
omarshahine/imessage-performance
Jun 24, 2026
Merged

perf(imessage): show typing sooner for slow replies#95621
omarshahine merged 4 commits into
mainfrom
omarshahine/imessage-performance

Conversation

@omarshahine

@omarshahine omarshahine commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Live iMessage turns can feel sluggish when the accepted message enters expensive setup before the model starts responding. In the profiled path, iMessage dispatch itself was quick, but context/session/model setup could leave the sender with no immediate feedback.

Read receipts were also on the accepted-turn critical path, so a slow private API read RPC could delay dispatch before the agent even started.

Why This Change Was Made

This moves iMessage private-API UI feedback off the critical path:

  • accepted direct iMessage turns now send an early native typing cue before attachment/history/context/model setup;
  • early typing is gated to direct, allowed sessions that use the instant/default typing mode and have imsg typing support;
  • early typing is explicitly stopped after dispatch completion or pre-dispatch failure, including fast command paths that never activate the normal typing controller;
  • read receipts are now best-effort and use a short-lived RPC client, so a slow read call cannot block dispatch or the monitor client's watch stream.

The direct typing target reuses the existing iMessage reply target builder, so SMS-vs-iMessage service selection remains consistent with final replies.

User Impact

Users most likely to benefit are people using OpenClaw over iMessage direct messages where responses can take several seconds because of long context, tool setup, model latency, or context-engine work. They should see the iMessage typing bubble sooner after the turn is accepted, which improves perceived responsiveness even when the underlying model path is still slow.

Required setup for the visible typing/read-receipt benefit:

  • iMessage channel enabled and receiving accepted direct-message turns;
  • imsg private API bridge available via imsg launch;
  • imsg status --json reporting RPC methods that include typing for early typing, and read for read receipts;
  • session.typingMode / agents.defaults.typingMode unset or set to instant;
  • source delivery not denied by session send policy;
  • direct chats only for the early typing cue. Group chats keep the existing behavior so group traffic does not show broad typing feedback.

The read-receipt optimization benefits hosts with private-API read support when channels.imessage.sendReadReceipts is not disabled.

Performance Savings

Live dogfood runs showed the user-visible read/typing feedback delay drop from about 10s send-to-read before this work to about 2s after moving the read receipt off the accepted-turn critical path. On the same setup, disabling the older 7s iMessage split-send debounce produced about 1s send-to-read, which confirmed this PR removes the private-API read RPC from the hot path and leaves the remaining delay to debounce/model/context work.

For slow model/context turns, the savings are mostly perceived responsiveness: the native iMessage typing cue is emitted before attachment/history/context/model setup, so users get immediate channel feedback while the expensive turn continues.

Evidence

Fresh live iMessage proof on commit 26a1d38904 (2026-06-23):

  • Ran Gateway from the PR checkout in the foreground after stopping the installed LaunchAgent; startup printed OpenClaw 2026.6.9 (26a1d38) and loaded extensions/imessage from this checkout.
  • A real direct iMessage inbound row arrived from a separate device/account: DB row 6340, is_from_me=0, text Test, created 2026-06-23T14:20:55.574Z.
  • The PR checkout processed that row after startup catch-up and marked it read: DB row 6340 had is_read=1 and non-zero date_read=803917326885792000.
  • No imessage: mark read failed or typing failure log appeared during the validation window.

Redacted live log sequence from the same PR checkout run:

2026-06-23T07:22:06.402-07:00 [routing] resolveAgentRoute: channel=imessage accountId=default peer=direct:*** bindings=0
2026-06-23T07:22:06.416-07:00 imessage inbound: chatId=3 from=imessage:*** len=276 preview="[iMessage *** +8h ...] ***: Test ..."
2026-06-23T07:22:07.026-07:00 message received: channel=imessage chatId=imessage:*** messageId=896 source=dispatchInboundMessage
2026-06-23T07:22:10.645-07:00 message queued: sessionKey=agent:lobster:imessage:direct:*** source=dispatch queueDepth=1 sessionState=idle
2026-06-23T07:22:10.674-07:00 message dispatch started: channel=imessage sessionKey=agent:lobster:imessage:direct:*** source=replyResolver
2026-06-23T07:22:22.449-07:00 preflightCompaction skipped: sessionKey=agent:lobster:imessage:direct:*** runtime=codex reason=codex_native_auto_compaction
2026-06-23T07:22:22.482-07:00 memoryFlush check: sessionKey=agent:lobster:imessage:direct:*** transcriptBytes=2509900 forceFlushByTranscriptSize=true
2026-06-23T07:22:49.109-07:00 message dispatch completed: channel=imessage sessionKey=agent:lobster:imessage:direct:*** source=replyResolver outcome=completed duration=38435ms
2026-06-23T07:22:49.111-07:00 message processed: channel=imessage chatId=imessage:*** messageId=896 outcome=completed duration=42081ms

Older local live proof:

  • Live dogfood read-status proof on the same host/setup: before this change, send-to-read feedback was roughly 10s; with this PR it was roughly 2s; disabling the older 7s inbound debounce on the same setup reached roughly 1s. That shows this PR removes the private-API read RPC from the accepted-turn hot path and leaves remaining delay to debounce/model/context work.
  • imsg status confirmed advanced IMCore features were available, including read receipts and typing.
  • Explicit private-API timing checks during validation: imsg read --chat-id 7 --json returned in 0.06s, 0.07s, and 0.11s; imsg typing --chat-id 7 --duration 1s --json returned in 1.15s, 1.20s, and 1.21s.

Local proof:

  • git diff --check passed.
  • node scripts/run-vitest.mjs extensions/imessage/src/monitor.last-route.test.ts passed, 33 tests.
  • .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main reported no accepted/actionable findings.
  • pnpm exec oxlint extensions/imessage/src/monitor/monitor-provider.ts passed after the lint follow-up.

Current PR CI proof on commit 26a1d389044:

Docs updated: https://docs.openclaw.ai/channels/imessage

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: imessage Channel integration: imessage size: M maintainer Maintainer-authored PR labels Jun 22, 2026
@omarshahine
omarshahine marked this pull request as ready for review June 22, 2026 00:51
@clawsweeper

clawsweeper Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 24, 2026, 6:26 PM ET / 22:26 UTC.

Summary
The PR moves iMessage read receipts off the accepted-turn critical path, starts eligible direct-message typing earlier, exports the direct reply target helper, and updates iMessage docs/tests.

PR surface: Source +66, Tests +258, Docs 0. Total +324 across 4 files.

Reproducibility: yes. Current main source shows read receipts awaited before dispatch and native typing created after context/reply setup, while the PR body provides live iMessage timing, DB, and log evidence; I did not run a fresh live iMessage turn in this read-only review.

Review metrics: 1 noteworthy metric.

  • Private API side effects moved: 2 moved. Read receipts move off the accepted-turn critical path and native typing starts earlier, which is the compatibility-sensitive behavior maintainers should notice before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Mantis proof suggestion
A native visual smoke would add useful reviewer proof for the visible early typing-bubble timing and cleanup path. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis visual task: verify direct iMessage shows an early typing bubble on accepted slow turns and clears it after reply completion on this PR.

Risk before merge

  • [P1] Read receipts become best-effort and no longer guarantee the chat is marked read before the agent turn starts; slow or failed private-API reads will surface after dispatch has already begun.
  • [P1] Direct iMessage progress and native typing timing change for accepted direct turns, so maintainers need to accept the new live transport semantics even with tests and proof.

Maintainer options:

  1. Accept iMessage UI Tradeoff (recommended)
    Merge after a maintainer confirms that best-effort read receipts and earlier direct typing are the desired default for this bundled channel.
  2. Request Native Visual Smoke
    Ask for a short native Messages/iMessage recording if maintainers want visual confirmation that the typing bubble starts early and clears cleanly beyond the existing logs.
  3. Defer To Latency Tracker
    Pause this PR if maintainers want the broader iMessage/Codex latency tracker to decide the final performance and instrumentation shape first.

Next step before merge

  • [P2] The protected maintainer label and accepted-turn transport tradeoffs require human acceptance; no narrow automated repair remains.

Security
Cleared: The diff touches iMessage runtime code, colocated tests, and one docs line only; no workflow, dependency, package, secret-handling, or supply-chain execution change was found.

Review details

Best possible solution:

Land after a maintainer explicitly accepts best-effort read receipts and earlier direct typing as the desired iMessage default, while leaving broader latency instrumentation to #96148.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main source shows read receipts awaited before dispatch and native typing created after context/reply setup, while the PR body provides live iMessage timing, DB, and log evidence; I did not run a fresh live iMessage turn in this read-only review.

Is this the best way to solve the issue?

Yes, with maintainer acceptance. The implementation stays in the iMessage plugin, reuses the existing direct reply target builder, preserves no-typing-capability progress options, and leaves broader latency instrumentation to the related tracker.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against c6f5725906dc.

Label changes

Label justifications:

  • P2: This is a bounded iMessage channel performance improvement with limited blast radius but real user-visible transport tradeoffs.
  • merge-risk: 🚨 compatibility: The PR changes ordering and guarantees for existing iMessage private-API read receipts and native typing feedback.
  • merge-risk: 🚨 message-delivery: The diff touches source-reply progress callback options and native typing behavior that can affect how direct iMessage turns surface progress.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): Sufficient: the PR body contains redacted live iMessage log/DB/timing evidence from a real direct inbound turn, and the final head adds focused fallback regression coverage without invalidating that proof.
  • proof: sufficient: Contributor real behavior proof is sufficient. Sufficient: the PR body contains redacted live iMessage log/DB/timing evidence from a real direct inbound turn, and the final head adds focused fallback regression coverage without invalidating that proof.
Evidence reviewed

PR surface:

Source +66, Tests +258, Docs 0. Total +324 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 108 42 +66
Tests 1 258 0 +258
Docs 1 1 1 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 367 43 +324

What I checked:

Likely related people:

  • omarshahine: Recent merged history introduced iMessage private-API support, typing keepalive behavior, and split-send behavior adjacent to this monitor path. (role: feature owner and recent area contributor; confidence: high; commits: e259751ec9c9, 02192bd27fd6, a0714a3d6855; files: extensions/imessage/src/monitor/monitor-provider.ts, extensions/imessage/src/monitor.last-route.test.ts, extensions/imessage/src/chat.ts)
  • steipete: Path history shows broad iMessage monitor, inbound processing, and plugin SDK boundary refactors that define the owner boundary this PR uses. (role: adjacent channel and plugin-SDK refactor owner; confidence: medium; commits: 1507a9701b83, 510f4276b5f3, fa87c6334aa6; files: extensions/imessage/src/monitor/monitor-provider.ts, extensions/imessage/src/monitor/inbound-processing.ts, src/plugin-sdk/reply-runtime.ts)
  • vincentkoc: Recent path history includes iMessage monitor retry/type fixes and channel documentation work near this surface. (role: recent adjacent iMessage contributor; confidence: medium; commits: 35a784c16563, ea71a59127a0, 2b4f600f9c; files: extensions/imessage/src/monitor/monitor-provider.ts, docs/channels/imessage.md)
  • Josh Lehman: Current-main blame on the changed monitor, chat, and docs lines points to a recent broad commit carrying this code forward, though not as feature-specific ownership. (role: recent line carrier; confidence: low; commits: da50a450d271; files: extensions/imessage/src/monitor/monitor-provider.ts, extensions/imessage/src/chat.ts, docs/channels/imessage.md)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jun 22, 2026
@omarshahine
omarshahine force-pushed the omarshahine/imessage-performance branch 2 times, most recently from 6bfc194 to c94ea0a Compare June 23, 2026 04:19
@omarshahine omarshahine removed the status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. label Jun 23, 2026
@omarshahine

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@omarshahine

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

2 similar comments
@omarshahine

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@omarshahine

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@omarshahine

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 23, 2026
@omarshahine

Copy link
Copy Markdown
Contributor Author

Fixed the remaining ClawSweeper blocker in 33f931f.

What changed:

  • Split the direct iMessage progress predicate from the native typing RPC predicate.
  • Kept suppressDefaultToolProgressMessages and allowProgressCallbacksWhenSourceDeliverySuppressed enabled for eligible direct/default iMessage turns even when imsg does not report typing support.
  • Kept native typing start/stop gated on supportsTyping.
  • Added regression coverage for an imsg capability list without typing.

Proof:

  • node scripts/run-vitest.mjs extensions/imessage/src/monitor.last-route.test.ts -> 34 passed
  • pnpm exec oxlint extensions/imessage/src/monitor/monitor-provider.ts extensions/imessage/src/monitor.last-route.test.ts
  • git diff --check
  • .agents/skills/autoreview/scripts/autoreview --mode local -> clean, no accepted/actionable findings

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@omarshahine

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

The requested predicate split and no-typing-capability regression test are now pushed at 33f931f. CI is green and the previous author action appears addressed.

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 24, 2026
@omarshahine
omarshahine force-pushed the omarshahine/imessage-performance branch 2 times, most recently from 553941f to b87e5dd Compare June 24, 2026 22:03
@omarshahine
omarshahine force-pushed the omarshahine/imessage-performance branch from b87e5dd to 65e9ad1 Compare June 24, 2026 22:21
@omarshahine
omarshahine merged commit f2af052 into main Jun 24, 2026
90 checks passed
@omarshahine
omarshahine deleted the omarshahine/imessage-performance branch June 24, 2026 22:31
@omarshahine

Copy link
Copy Markdown
Contributor Author

Merged via squash.

Thanks @omarshahine!

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 25, 2026
Merged via squash.

Prepared head SHA: 65e9ad1
Co-authored-by: omarshahine <[email protected]>
Co-authored-by: omarshahine <[email protected]>
Reviewed-by: @omarshahine
QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
Merged via squash.

Prepared head SHA: 65e9ad1
Co-authored-by: omarshahine <[email protected]>
Co-authored-by: omarshahine <[email protected]>
Reviewed-by: @omarshahine
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: imessage Channel integration: imessage docs Improvements or additions to documentation maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: M status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant