Skip to content

Matrix channel: replies in same room don't resolve thread ID (auto-injection missing) #32744

@braminatorh

Description

@braminatorh

Problem

When using the Matrix channel plugin, replies sent to the same room do not resolve the thread ID automatically. This causes replies to appear as new messages instead of threaded replies.

Slack and Telegram have auto-thread-injection logic in resolveAndApplyOutboundThreadId() (via slackAutoThreadId and telegramAutoThreadId), but Matrix has no equivalent.

Current Workaround

We patch dist/reply-*.js after each update to add a resolveMatrixAutoThreadId() function that:

  1. Checks if ctx.channel === "matrix" and no explicit threadId is set
  2. Looks up currentThreadTs and currentChannelId from tool context
  3. Compares normalized target room with current room
  4. Returns currentThreadTs as the thread ID if they match

The patched line changes from:

const resolved = threadId ?? slackAutoThreadId ?? telegramAutoThreadId;

To:

const resolved = threadId ?? slackAutoThreadId ?? telegramAutoThreadId ?? matrixAutoThreadId;

Expected Behavior

Matrix should have native auto-thread-injection, similar to Slack and Telegram. When an agent replies to a message in a Matrix room, the reply should be threaded under the original message automatically.

Environment

  • OpenClaw 2026.3.1
  • Matrix plugin with Conduwuit homeserver
  • Using per-room agent sessions (each room gets its own session)

Patch Code

# resolveMatrixAutoThreadId function added before resolveAndApplyOutboundThreadId
function resolveMatrixAutoThreadId(params) {
    const context = params.toolContext;
    if (!context?.currentThreadTs || !context.currentChannelId) return;
    const to = params.to?.trim()?.toLowerCase();
    const current = context.currentChannelId?.trim()?.toLowerCase();
    if (!to || !current) return;
    const normalizedTo = to.startsWith("room:") ? to.slice(5) : to;
    const normalizedCurrent = current.startsWith("room:") ? current.slice(5) : current;
    if (normalizedTo !== normalizedCurrent) return;
    return context.currentThreadTs;
}

This has been running stable in production since 2026-02-28.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions