Summary
Feishu topic/thread messages currently only preserve a concrete reply target in OriginatingTo for bare /new or /reset messages. For normal business messages inside a Feishu topic, delayed agent replies such as subagent completion/announce can lose the original message_id reply target and may create a new topic instead of replying inside the original topic.
Environment
- OpenClaw:
2026.5.6
@larksuite/openclaw-lark: 2026.5.20
- Feishu group chat mode:
group_message_type=thread
threadSession=true behavior is active: inbound session keys include :thread:omt_*
Observed behavior
- A user sends a normal message in an existing Feishu topic and mentions an OpenClaw agent.
- Immediate parent-agent replies land in the original topic.
- A delayed reply triggered by subagent completion/announce may be sent to the bare chat target, e.g.
chat:oc_*, which creates a new topic / lands outside the original topic.
The issue is not thread session detection itself. Logs showed inbound routing correctly used a session key like:
agent:<agent-id>:feishu:group:oc_REDACTED:thread:omt_REDACTED
The missing piece was carrying the concrete Feishu message_id reply target into the delayed outbound route.
Expected behavior
For every Feishu topic message, not only /new or /reset, OriginatingTo should preserve an encoded route target containing:
- the chat target
__feishu_reply_to=<message_id>
__feishu_thread_id=<thread_id>
Then delayed replies can resolve the encoded route and call Feishu reply API with reply_in_thread=true.
Current code behavior
In src/messaging/inbound/dispatch.ts / compiled dispatch.js, originatingTo is currently guarded by isBareNewOrReset && dc.isThread:
const originatingTo = isBareNewOrReset && dc.isThread
? encodeFeishuRouteTarget({
target: dc.feishuTo,
replyToMessageId: params.replyToMessageId ?? params.ctx.messageId,
threadId: dc.ctx.threadId,
})
: undefined;
This means normal topic messages do not populate OriginatingTo with the concrete reply target.
Verified local patch
We locally patched this to encode OriginatingTo for every topic message:
- const originatingTo = isBareNewOrReset && dc.isThread
+ const originatingTo = dc.isThread && dc.ctx.threadId
? encodeFeishuRouteTarget({
target: dc.feishuTo,
replyToMessageId: params.replyToMessageId ?? params.ctx.messageId,
threadId: dc.ctx.threadId,
})
: undefined;
After applying this patch, delayed subagent announce/completion replies successfully returned to the original topic. Logs showed:
feishu: sendText: target=chat:oc_REDACTED#__feishu_reply_to=om_REDACTED&__feishu_thread_id=omt_REDACTED
feishu: resolved reply target from encoded originating route
feishu: replying to message om_REDACTED (msg_type=post, thread=true)
A/B validation
We also tested whether To needed to be changed to the encoded route. It does not appear necessary for this path.
A/B state:
To: dc.feishuTo,
OriginatingTo: opts.originatingTo ?? dc.feishuTo,
With only the dispatch.js / OriginatingTo patch above, subagent announce still replied to the original topic. This suggests the minimal fix is only to broaden OriginatingTo for all Feishu topic messages.
Suggested fix
Change the originatingTo guard from:
isBareNewOrReset && dc.isThread
to:
dc.isThread && dc.ctx.threadId
Optionally add a comment explaining that delayed inter-session/subagent replies need the concrete Feishu message_id because replying inside a Feishu topic requires replying to a message, not only sending to a chat/thread id.
Summary
Feishu topic/thread messages currently only preserve a concrete reply target in
OriginatingTofor bare/newor/resetmessages. For normal business messages inside a Feishu topic, delayed agent replies such as subagent completion/announce can lose the originalmessage_idreply target and may create a new topic instead of replying inside the original topic.Environment
2026.5.6@larksuite/openclaw-lark:2026.5.20group_message_type=threadthreadSession=truebehavior is active: inbound session keys include:thread:omt_*Observed behavior
chat:oc_*, which creates a new topic / lands outside the original topic.The issue is not thread session detection itself. Logs showed inbound routing correctly used a session key like:
The missing piece was carrying the concrete Feishu
message_idreply target into the delayed outbound route.Expected behavior
For every Feishu topic message, not only
/newor/reset,OriginatingToshould preserve an encoded route target containing:__feishu_reply_to=<message_id>__feishu_thread_id=<thread_id>Then delayed replies can resolve the encoded route and call Feishu reply API with
reply_in_thread=true.Current code behavior
In
src/messaging/inbound/dispatch.ts/ compileddispatch.js,originatingTois currently guarded byisBareNewOrReset && dc.isThread:This means normal topic messages do not populate
OriginatingTowith the concrete reply target.Verified local patch
We locally patched this to encode
OriginatingTofor every topic message:After applying this patch, delayed subagent announce/completion replies successfully returned to the original topic. Logs showed:
A/B validation
We also tested whether
Toneeded to be changed to the encoded route. It does not appear necessary for this path.A/B state:
With only the
dispatch.js/OriginatingTopatch above, subagent announce still replied to the original topic. This suggests the minimal fix is only to broadenOriginatingTofor all Feishu topic messages.Suggested fix
Change the
originatingToguard from:to:
Optionally add a comment explaining that delayed inter-session/subagent replies need the concrete Feishu
message_idbecause replying inside a Feishu topic requires replying to a message, not only sending to a chat/thread id.