Skip to content

fix(imessage): make inbound image attachments readable by agents#78580

Merged
omarshahine merged 3 commits into
openclaw:mainfrom
homer-byte:fix/imessage-stage-inbound-attachments
May 13, 2026
Merged

fix(imessage): make inbound image attachments readable by agents#78580
omarshahine merged 3 commits into
openclaw:mainfrom
homer-byte:fix/imessage-stage-inbound-attachments

Conversation

@homer-byte

@homer-byte homer-byte commented May 6, 2026

Copy link
Copy Markdown
Contributor

Summary

  • stage native iMessage inbound attachments into OpenClaw-managed inbound media before dispatch
  • convert HEIC/HEIF iMessage photos to JPEG with macOS sips so image-understanding tools can read iPhone photos
  • keep remote-host iMessage attachment handling on the existing raw-path contract, and remove a stale Codex test helper that was breaking changed-lane extension lint

Problem

Native iMessage image attachments were not reliably getting through to agents/tools. In practice, iPhone screenshots/photos could arrive as raw ~/Library/Messages/Attachments/... HEIC paths; those paths are outside the image tool's safe media roots, and HEIC decoding can also fail depending on the local image backend. The result was that users could send an iMessage image, but the agent could not actually inspect it without manual copying/conversion.

Real behavior proof

  • Behavior or issue addressed: Native iMessage inbound HEIC photos were delivered to agents as raw ~/Library/Messages/Attachments/... paths, which downstream image tooling could not safely read or decode. This patch stages local native iMessage attachments into OpenClaw-managed inbound media and converts HEIC/HEIF to JPEG before dispatch.
  • Real environment tested: macOS OpenClaw setup on MACMINI-2026, using a real inbound iMessage .heic file previously captured in OpenClaw media storage.
  • Exact steps or command run after this patch: Ran the new stageIMessageAttachments code path via pnpm exec tsx tmp-openclaw-imessage-stage-proof.ts /Users/openclaw/.openclaw/media/inbound/6f7b474f-4798-4619-994f-3566c5b472e1.heic, then verified the staged output with file, and sent the staged JPEG through the image-understanding tool.
  • Evidence after fix: Console output from the patched code path:
[
  {
    "path": "/Users/openclaw/.openclaw/media/inbound/6f7b474f-4798-4619-994f-3566c5b472e1---5556a81c-f584-4ca9-90f7-5646d70cfd86.jpg",
    "contentType": "image/jpeg"
  }
]

$ file /Users/openclaw/.openclaw/media/inbound/6f7b474f-4798-4619-994f-3566c5b472e1---5556a81c-f584-4ca9-90f7-5646d70cfd86.jpg
JPEG image data, JFIF standard 1.01, ... baseline, precision 8, 4096x2304, components 3
  • Observed result after fix: The real inbound HEIC was staged as an OpenClaw inbound media JPEG with contentType: "image/jpeg"; file confirmed a decodable 4096x2304 JPEG, and the image-understanding tool successfully decoded and described the staged JPEG.
  • What was not tested: Did not run a full live Gateway restart with a new iMessage photo in this PR branch; the tested path is the patched staging/conversion function using a real inbound iMessage HEIC fixture.

Tests

  • pnpm exec oxfmt --check --threads=1 extensions/imessage/src/monitor/monitor-provider.ts extensions/imessage/src/monitor/media-staging.ts extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor/types.ts CHANGELOG.md
  • pnpm exec oxlint extensions/imessage/src/monitor/monitor-provider.ts extensions/imessage/src/monitor/media-staging.ts extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor/types.ts
  • pnpm test extensions/imessage
  • pnpm check:changed

@openclaw-barnacle openclaw-barnacle Bot added channel: imessage Channel integration: imessage extensions: codex triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. size: M labels May 6, 2026
@homer-byte homer-byte force-pushed the fix/imessage-stage-inbound-attachments branch 3 times, most recently from d612cdf to f715416 Compare May 6, 2026 18:10
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 6, 2026

@byungskers byungskers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on the HEIC-to-JPEG conversion path! A few observations:

  1. sips dependency: The conversion relies on macOS sips being available. Should there be a runtime check or fallback when sips is missing (e.g., non-macOS hosts or sandboxed environments)?

  2. Error handling for conversion failures: If sips fails or returns a non-zero exit code, the current path returns an empty attachments array. Would it be better to preserve the original HEIC path as a fallback so the agent at least sees something, even if downstream tools can't decode it?

  3. Cleanup on failure: If sips partially writes a corrupted JPEG before failing, should the temp output file be cleaned up to avoid polluting the inbound media directory?

Tests look solid and the real behavior proof is thorough. Just these edge cases to consider.

@clawsweeper

clawsweeper Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

Summary
The PR stages native inbound iMessage attachments into OpenClaw-managed media and converts local HEIC/HEIF images to JPEG before dispatch while preserving remote-host raw-path handling.

Reproducibility: yes. Current main is source-reproducible because it forwards validated iMessage original_path values into agent media fields, and the discussion includes real v2026.5.12-beta.3 HEIC evidence showing that exact raw Messages path reached the prompt.

Real behavior proof
Sufficient (terminal): Sufficient terminal proof is supplied: the PR body shows a real inbound HEIC converted to managed JPEG media and decoded by the image-understanding tool.

Next step before merge
No repair lane is needed; this is an active focused PR with sufficient proof and no blocking findings from this pass.

Security
Cleared: Cleared: the diff bounds local file staging, uses execFile without a shell, checks allowed roots and sizes, and writes through the managed media store.

Review details

Best possible solution:

Land the plugin-owned staging/conversion fix after normal maintainer merge gates, keeping core media root policy unchanged.

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

Yes. Current main is source-reproducible because it forwards validated iMessage original_path values into agent media fields, and the discussion includes real v2026.5.12-beta.3 HEIC evidence showing that exact raw Messages path reached the prompt.

Is this the best way to solve the issue?

Yes. The PR keeps the fix at the iMessage plugin boundary, stages only after dispatch policy and loop guards, preserves remote-host raw paths, and avoids widening generic image-tool safe roots.

What I checked:

Likely related people:

  • homer-byte: Has a recently merged iMessage preview-attachment fix on the same monitor path and is proposing this focused staging change. (role: recent adjacent contributor; confidence: high; commits: ba1f4271e8d2; files: extensions/imessage/src/monitor/monitor-provider.ts, extensions/imessage/src/monitor/types.ts)
  • omarshahine: Recent native iMessage private-API, catchup, and reaction work touches the same inbound monitor path, and they supplied real HEIC evidence in the discussion. (role: feature owner; confidence: high; commits: e259751ec9c9, 81e0a1a99bc4, d7a924862044; files: extensions/imessage/src/monitor/monitor-provider.ts, extensions/imessage/src/monitor/inbound-processing.ts)
  • steipete: Recent plugin SDK/media-root and native iMessage action work is adjacent to the attachment staging and SDK boundary used by this PR. (role: adjacent owner; confidence: medium; commits: fe79d85ae0cb, c077af987f1e, 827b0de0ce74; files: extensions/imessage/src/monitor/monitor-provider.ts, extensions/imessage/src/media-contract.ts, src/agents/tools/media-tool-shared.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against 2a67a7f65e26.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@homer-byte homer-byte force-pushed the fix/imessage-stage-inbound-attachments branch from f715416 to 8c8b623 Compare May 6, 2026 18:54
@homer-byte

homer-byte commented May 6, 2026

Copy link
Copy Markdown
Contributor Author

Updated the PR for the security review.

Changes pushed in 8c8b623b:

  • Moved local iMessage attachment staging until after resolveIMessageInboundDecision returns dispatch and after the echo-loop rate-limit guard.
  • Kept pre-decision media placeholders based only on validated attachment metadata, not file reads/conversion.
  • Preserved the remote-host raw-path contract.
  • Added monitor.media-policy.test.ts to prove a dropped group message with a valid local attachment does not call stageIMessageAttachments.

On the edge-case questions from @byungskers:

  • sips failure/missing binary already falls back inside readAttachmentBuffer: it logs the conversion failure and stages the original attachment into managed media instead of dropping it.
  • Temp JPEG cleanup is already in a finally block with fs.rm(..., { force: true }), so partial temp output is removed even on conversion failure.
  • Since native iMessage is macOS-only, sips is a reasonable first conversion path; the fallback keeps behavior safe if it is unavailable.

Validated after the update:

  • pnpm exec oxfmt --check --threads=1 extensions/imessage/src/monitor/monitor-provider.ts extensions/imessage/src/monitor.media-policy.test.ts extensions/imessage/src/monitor/media-staging.ts extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor/types.ts CHANGELOG.md
  • pnpm exec oxlint extensions/imessage/src/monitor/monitor-provider.ts extensions/imessage/src/monitor.media-policy.test.ts extensions/imessage/src/monitor/media-staging.ts extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor/types.ts
  • pnpm test extensions/imessage → 177 passed
  • pnpm check:changed

Re-review progress:

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@homer-byte homer-byte force-pushed the fix/imessage-stage-inbound-attachments branch from 8c8b623 to 8b5385d Compare May 7, 2026 19:57
@openclaw-barnacle openclaw-barnacle Bot removed extensions: codex proof: sufficient ClawSweeper judged the real behavior proof convincing. labels May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@homer-byte homer-byte force-pushed the fix/imessage-stage-inbound-attachments branch from 8b5385d to 460dd6d Compare May 7, 2026 20:05
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@homer-byte homer-byte force-pushed the fix/imessage-stage-inbound-attachments branch from 460dd6d to a6b2502 Compare May 7, 2026 20:14
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@omarshahine

Copy link
Copy Markdown
Contributor

@clawsweeper re-review

@omarshahine

omarshahine commented May 13, 2026

Copy link
Copy Markdown
Contributor

Confirming the bug shape on a real inbound HEIC (v2026.5.12-beta.3)

Pulled from a separate machine running OpenClaw v2026.5.12-beta.3 (cc46ca9), native iMessage path (imsg private-API), channels.imessage.includeAttachments: true.

chat.db row for a real inbound iPhone HEIC (IMG_9372.heic):

{
  "transfer_name": "IMG_9372.heic",
  "original_path": "~/Library/Messages/Attachments/d7/07/F92CCA7E-3434-4B5E-BCAA-7EF25D83FB0F/IMG_9372.heic",
  "mime_type": "image/heic",
  "uti": "public.heic"
}

What the unpatched monitor handed to the agent (from session JSONL — same text content the gpt-5.5 prompt received):

[media attached: /Users/<user>/Library/Messages/Attachments/d7/07/.../IMG_9372.heic (image/heic) | /Users/<user>/Library/Messages/Attachments/d7/07/.../IMG_9372.heic]
To send an image back, prefer the message tool ...

So the agent was handed a raw ~/Library/Messages/Attachments/... HEIC path with image/heic content type — exactly the pre-staging shape the PR's repro describes. No JPEG conversion, no staging into the OpenClaw inbound-media root.

The PR's stageIMessageAttachments + HEIC→JPEG sips pass would have produced a .openclaw/media/inbound/<id>.jpg path with image/jpeg, which the image-understanding tool can actually decode.

Fix LGTM — addresses the observed delivery shape on a real HEIC.

(I'll send a fresh HEIC end-to-end through this gateway and post the after-the-merge confirmation once #78580 lands here.)

Re-review progress:

@clawsweeper

clawsweeper Bot commented May 13, 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.

Re-review progress:

@homer-byte

Copy link
Copy Markdown
Contributor Author

Follow-up pushed in adf93ea668c to address the two ClawSweeper blockers.

Changes:

  • Bounded the HEIC/HEIF sips conversion with an explicit 15s timeout, 64 KiB output buffer, and SIGKILL timeout kill signal before inbound dispatch waits on it.
  • Removed the unrelated core target-prefix routing change and restored the existing imessage: provider-prefix cron delivery contract.

Validated locally:

  • pnpm exec oxfmt --check --threads=1 extensions/imessage/src/monitor/monitor-provider.ts extensions/imessage/src/monitor.media-policy.test.ts extensions/imessage/src/monitor/media-staging.ts extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor/types.ts src/cron/delivery.test.ts src/infra/outbound/channel-target-prefix.ts CHANGELOG.md
  • pnpm exec oxlint extensions/imessage/src/monitor/monitor-provider.ts extensions/imessage/src/monitor.media-policy.test.ts extensions/imessage/src/monitor/media-staging.ts extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor/types.ts src/cron/delivery.test.ts src/infra/outbound/channel-target-prefix.ts
  • pnpm test extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor.media-policy.test.ts src/cron/delivery.test.ts
  • pnpm test extensions/imessage → 358 passed
  • pnpm check:changed

@clawsweeper re-review

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 13, 2026
@clawsweeper

clawsweeper Bot commented May 13, 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.

Re-review progress:

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 13, 2026
@homer-byte homer-byte force-pushed the fix/imessage-stage-inbound-attachments branch from adf93ea to 97ddb8f Compare May 13, 2026 12:40
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 13, 2026
@homer-byte homer-byte force-pushed the fix/imessage-stage-inbound-attachments branch from 97ddb8f to 0fac83f Compare May 13, 2026 12:45
@homer-byte

Copy link
Copy Markdown
Contributor Author

Rebased again on current main after the branch flipped to conflicting; resolved the monitor-provider.ts conflict with the newer reaction system-event path by preserving that early return and keeping local attachment staging after dispatch policy/loop guards.

New head: 0fac83f34f1.

Validated locally after the rebase:

  • ./node_modules/.bin/oxfmt --check --threads=1 extensions/imessage/src/monitor/monitor-provider.ts extensions/imessage/src/monitor.media-policy.test.ts extensions/imessage/src/monitor/media-staging.ts extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor/types.ts CHANGELOG.md
  • ./node_modules/.bin/oxlint extensions/imessage/src/monitor/monitor-provider.ts extensions/imessage/src/monitor.media-policy.test.ts extensions/imessage/src/monitor/media-staging.ts extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor/types.ts
  • ./node_modules/.bin/vitest run extensions/imessage/src/monitor/media-staging.test.ts extensions/imessage/src/monitor.media-policy.test.ts → 5 passed
  • ./node_modules/.bin/vitest run extensions/imessage → 40 files / 368 tests passed
  • pnpm check:changed

GitHub now reports the PR as mergeable again; checks are rerunning on the new head.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 13, 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.

Re-review progress:

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 13, 2026
@omarshahine omarshahine self-assigned this May 13, 2026

@omarshahine omarshahine left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The fix stays inside the iMessage plugin boundary, stages only after inbound policy/loop guards, keeps remote-host raw path behavior, and has focused coverage for staging, HEIC conversion, and drop-policy behavior.

Merge evidence checked: ClawSweeper reports no blocking findings with sufficient real behavior proof, live maintainer proof confirms the raw HEIC bug shape on v2026.5.12-beta.3, and the current head 0fac83f has green CI/status rollup for lint, tests, docs, boundaries, build smoke, security, and real behavior proof.

@omarshahine omarshahine merged commit 1d6e5f7 into openclaw:main May 13, 2026
109 checks passed
@omarshahine

Copy link
Copy Markdown
Contributor

Landed via squash merge.

  • Source head: 0fac83f
  • Merge commit: 1d6e5f7
  • Gate/proof: current PR status rollup was green for CI, build smoke, lint, tests, boundary checks, security, docs, and Real behavior proof; ClawSweeper reported no blocking findings and sufficient real behavior proof.

Thanks @homer-byte.

steipete pushed a commit that referenced this pull request May 13, 2026
)

Stage native iMessage inbound attachments into managed media and convert HEIC/HEIF images to JPEG before dispatch. Thanks @homer-byte.

(cherry picked from commit 1d6e5f7)
l3ocifer pushed a commit to l3ocifer/frack-openclaw that referenced this pull request May 13, 2026
…nclaw#78580)

Stage native iMessage inbound attachments into managed media and convert HEIC/HEIF images to JPEG before dispatch. Thanks @homer-byte.
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
…nclaw#78580)

Stage native iMessage inbound attachments into managed media and convert HEIC/HEIF images to JPEG before dispatch. Thanks @homer-byte.
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
…nclaw#78580)

Stage native iMessage inbound attachments into managed media and convert HEIC/HEIF images to JPEG before dispatch. Thanks @homer-byte.
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
…nclaw#78580)

Stage native iMessage inbound attachments into managed media and convert HEIC/HEIF images to JPEG before dispatch. Thanks @homer-byte.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: imessage Channel integration: imessage proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants