Skip to content

iMessage: pass reply_to_guid to imsg for native threaded replies #51892

Description

@rancur

Summary

When replying to an iMessage, OpenClaw correctly tracks the replyToId (message GUID) and prepends a [[reply_to:<guid>]] tag to the outbound message text via prependReplyTagIfNeeded(). However, this tag is not extracted and passed as reply_to_guid in the params sent to the imsg RPC send call.

The imsg CLI (v0.4.0) already supports reply_to_guid / replyToGUID in its send API, which creates a native iMessage threaded reply (using associatedMessageGuid). The plumbing exists on both sides — the bridge is just missing.

Current behavior

  1. Gateway resolves replyToId from the incoming message
  2. prependReplyTagIfNeeded() prepends [[reply_to:<guid>]] to the message text
  3. sendMessageIMessage() builds params = { text, service, region } — no reply_to_guid
  4. client.request("send", params) sends to imsg — reply tag stays as literal text prefix
  5. Reply shows up as a standalone message, not a threaded reply

Expected behavior

  1. Extract the GUID from the [[reply_to:]] tag
  2. Strip the tag from the message text
  3. Pass reply_to_guid in the params to imsg
  4. Reply shows up as a native iMessage threaded reply

Suggested fix

In src/imessage/send.ts, after prependReplyTagIfNeeded():

message = prependReplyTagIfNeeded(message, opts.replyToId);

// Extract reply_to tag and pass as native reply_to_guid to imsg
const replyTagMatch = message.match(/^\s*\[\[\s*reply_to\s*:\s*([^\]\n]+)\s*\]\]\s*/i);
const replyToGuid = replyTagMatch ? replyTagMatch[1].trim() : undefined;
if (replyTagMatch) message = message.slice(replyTagMatch[0].length);

const params: Record<string, string> = {
  text: message,
  service: service || "auto",
  region,
};
if (replyToGuid) params.reply_to_guid = replyToGuid;

This is a ~4 line change. The imsg binary already handles reply_to_guid to set associatedMessageGuid on the outbound message.

Environment

  • OpenClaw: 2026.3.13 (61d171a)
  • imsg: 0.4.0
  • macOS 26.2.0
  • Channel: BlueBubbles (iMessage via Private API)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions