openclaw - ✅(Solved) Fix [Bug]: [Feishu] group_topic session: assistant uses action=send instead of thread-reply, reply not posted in topic thread [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#74903Fetched 2026-05-01 05:40:09
View on GitHub
Comments
1
Participants
2
Timeline
9
Reactions
2
Timeline (top)
cross-referenced ×2mentioned ×2subscribed ×2commented ×1

Summary

When a Feishu group chat message triggers a group_topic-scoped session, the assistant's reply is sent as a normal group message rather than as a thread (话题) reply to the original message.

Root Cause

buildGroupChatContext() in get-reply-CfL1pJQm.js generates the system prompt:

"Normal final replies are private and are not automatically sent to this group chat. To post visible output here, use the message tool with action=send..."

For group_topic sessions, this instruction does not tell the assistant to use action=thread-reply with the triggering messageId. As a result, the assistant calls message(action="send") which resolves to the plain chatId (e.g. oc_xxx) without any topic/thread context.

In channel-BHQ-AXGx.js, replyInThread is only set to true when ctx.action === "thread-reply":

replyInThread: ctx.action === "thread-reply"

Fix Action

Fixed

PR fix notes

PR #75159: fix(feishu): nudge LLM to thread-reply in group_topic sessions (#74903)

Description (problem / solution / changelog)

### Summary

When a Feishu group chat is configured with `groupSessionScope: "group_topic"`
or `"group_topic_sender"`, the assistant's visible reply is sent as a normal
group message instead of a thread (话题) reply to the triggering message.

Per @zhangkang-wy's analysis on #74903:

- The shared system prompt produced by `buildGroupChatContext()`
  (`src/auto-reply/reply/groups.ts`) tells the LLM:
  "To post visible output here, use the message tool with **action=send**…"
- For Feishu topic-mode sessions that instruction is wrong: the runtime
  resolves `action=send` to the plain `chatId` without any topic context,
  so the reply lands in the main chat instead of in the topic thread.
- Feishu's channel runtime already supports the right shape:
  `extensions/feishu/src/channel.ts` maps
  `ctx.action === "thread-reply"` → `replyInThread: true` and uses the
  `messageId` param as the topic root. The bug is purely that the LLM
  isn't told to use `thread-reply` for these sessions.

### Fix

Add a Feishu-owned system-prompt addendum that overrides the generic
"use action=send" instruction when the session is topic-scoped, telling
the LLM to use `action="thread-reply"` with the topic's root `messageId`
instead. The hint flows through the existing `GroupSystemPrompt`
template field (already plumbed through `extraSystemPrompt`), so no
core changes are needed.

Per `extensions/AGENTS.md` (Owner boundary: "If a bug names an
extension or its dependency, start in that extension and add a generic
core seam only when multiple owners need it"), the fix lives entirely
inside `extensions/feishu/`.

Changes:

- `extensions/feishu/src/bot-content.ts`: new `isFeishuTopicGroupSessionScope`
  predicate and `buildFeishuGroupTopicPromptHint(...)` that returns the
  topic-aware instruction string when the session is `group_topic`/
  `group_topic_sender` and a topic root messageId is available.
- `extensions/feishu/src/bot.ts`: at the `GroupSystemPrompt` site for the
  outbound `TemplateContext`, compose the user-configured group system
  prompt with the new topic hint (newline-separated; either may be empty).
  The topic root id passed to the helper is `ctx.rootId ?? ctx.messageId`,
  matching the same precedence used for `replyTargetMessageId` in topic
  sessions a few lines below.
- `extensions/feishu/src/bot-content.topic-prompt.test.ts`: 8 unit tests
  covering scope predicate, hint emission for both topic scopes,
  non-topic / undefined / blank-id cases, and whitespace trimming.

### Verification

- `pnpm test extensions/feishu` — 700/700 pass (62 files).
- `pnpm tsgo:extensions` — clean.
- `pnpm tsgo:extensions:test` — clean.
- `pnpm exec oxfmt --check --threads=1 …` — clean on touched files.

### Notes

- This is a system-prompt-only nudge. The runtime already routes
  `action=thread-reply` correctly; no behavior change for non-topic
  sessions or for groups without a topic-scoped session config.
- A direct-conversation user is unaffected because `GroupSystemPrompt`
  is only set when `isGroup` is true.
- Future generalization (cross-channel "topic mode" prompt seam) would
  fit `src/auto-reply/reply/groups.ts` once a second channel needs it.

Closes #74903

Changed files

  • extensions/feishu/src/bot-content.topic-prompt.test.ts (added, +91/-0)
  • extensions/feishu/src/bot-content.ts (modified, +22/-0)
  • extensions/feishu/src/bot.ts (modified, +12/-1)

PR #75364: fix(feishu): route message(action=send) through inbound thread in gro…

Description (problem / solution / changelog)

Fixes #74903

Summary

  • Problem: In a Feishu group_topic (话题) session, when the assistant calls message(action="send"), the action handler sends to the chat root with replyInThread: false, so visible replies fall out of the topic thread.
  • Why it matters: Operators using Feishu topic threads see the bot reply as a normal group message. The conversation is split: ordinary mention replies thread correctly, but the message-tool path doesn't.
  • What changed: In extensions/feishu/src/channel.ts, when the action handler routes action === "send" and the active session is a group_topic or group_topic_sender scope (detected via parseFeishuConversationId(ctx.sessionKey)) and ctx.toolContext.currentMessageId is available, set replyToMessageId = currentMessageId and replyInThread = true. Existing explicit action === "thread-reply" behavior is unchanged.
  • What did NOT change (scope boundary):
    • Plain group and group_sender sessions: send still goes to chat root (replyInThread: false).
    • thread-reply action: unchanged path; still requires explicit messageId param.
    • Non-Feishu channels (Telegram, Slack, Discord, etc.): untouched.
    • Auto-reply prompt-builder in src/auto-reply/reply/groups.ts: not modified — the fix lives entirely in the Feishu plugin per the owner-boundary rule in extensions/CLAUDE.md ("fix owner-specific behavior in the owner module").
    • System prompt wording for messageToolOnly group chat: unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Integrations
  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #74903
  • This PR fixes a bug or regression

Root Cause

  • Root cause: extensions/feishu/src/channel.ts:743,763 hardcoded replyInThread: ctx.action === "thread-reply". The send action ignores the session's topic-mode context entirely.
  • Missing detection / guardrail: No regression test asserted topic-mode send behavior. The only send tests covered the plain group case (default replyInThread: false); the only thread-reply tests covered the explicit thread-reply action.
  • Contributing context: parseFeishuConversationId already exists in the same plugin and exposes scope: "group_topic" | "group_topic_sender". The plumbing was available; the action handler just wasn't consulting it.

Regression Test Plan

Coverage level that should have caught this: plugin-action unit test in extensions/feishu/src/channel.test.ts. The new tests cover the four cases that bound the fix:

  1. send from a group_topic session (with currentMessageId) → auto-promotes to thread reply against the inbound trigger.
  2. send from a group_topic_sender session (with currentMessageId) → also auto-promotes.
  3. send from a plain group session → no change in behavior; replyInThread: false.
  4. send from a group_topic session without currentMessageId → defensive guard: no auto-promote (we don't have a parent to thread against).

Human Verification

What I locally verified:

  • pnpm test extensions/feishu/src/channel.test → 74 Vitest shards pass (66s).
  • Manual code reading of parseFeishuConversationId confirms it's already used in channel.ts:315,342,1163 for the same kind of session-key parsing — no new dependency or contract added.
  • New helper isFeishuGroupTopicSessionKey is colocated with existing is* helpers near the top of channel.ts; defensive against null/undefined/non-Feishu session keys.

What I did NOT verify:

  • Live Feishu group-topic delivery (no Feishu test app available locally; test suite uses mocks only).
  • Whether the assistant model in real sessions actually routes through message(action=send) instead of natural reply when messageToolOnly is in effect — I trust the reporter's behavior trace on this. If the model uses a different action, the fix is a no-op (safe fallback).
  • Behavior under edge session keys (e.g. core wraps sessionKey with extra prefix segments) — parseFeishuConversationId only matches when the string ends in :topic:<topicId> etc., so non-matching wrappers fall through to no-promote, matching the existing path.

Greptile / Reviewer Notes

  • Considered fixing this in core (src/auto-reply/reply/groups.ts:235) by changing the prompt instruction. Rejected because:
    • group_topic is a Feishu-specific session-key scope; no other channel uses that exact discriminator.
    • Per extensions/CLAUDE.md, owner-specific behavior stays owner-specific.
    • The prompt fix would still need the channel layer to honor the topic context for the resulting thread-reply action — Approach B fixes the root behavior without depending on the model emitting the right action name.
  • The reporter's note also flagged the prompt instruction as part of the bug. The prompt text is still accurate for plain group sessions; only the group_topic channel routing is wrong, which is what this PR fixes.

Changed files

  • extensions/feishu/src/channel.test.ts (modified, +88/-0)
  • extensions/feishu/src/channel.ts (modified, +25/-3)

Code Example

replyInThread: ctx.action === "thread-reply"

### Steps to reproduce

# Summary

When a Feishu group chat message triggers a `group_topic`-scoped session, the assistant's reply is sent as a normal group message rather than as a thread (话题) reply to the original message.

## Root Cause

`buildGroupChatContext()` in `get-reply-CfL1pJQm.js` generates the system prompt:

> "Normal final replies are private and are not automatically sent to this group chat. To post visible output here, use the message tool with **action=send**..."

For `group_topic` sessions, this instruction does not tell the assistant to use `action=thread-reply` with the triggering `messageId`. As a result, the assistant calls `message(action="send")` which resolves to the plain `chatId` (e.g. `oc_xxx`) without any topic/thread context.

In `channel-BHQ-AXGx.js`, `replyInThread` is only set to `true` when `ctx.action === "thread-reply"`:

---

replyInThread: ctx.action === "thread-reply"

### Actual behavior

# Summary

When a Feishu group chat message triggers a `group_topic`-scoped session, the assistant's reply is sent as a normal group message rather than as a thread (话题) reply to the original message.

## Root Cause

`buildGroupChatContext()` in `get-reply-CfL1pJQm.js` generates the system prompt:

> "Normal final replies are private and are not automatically sent to this group chat. To post visible output here, use the message tool with **action=send**..."

For `group_topic` sessions, this instruction does not tell the assistant to use `action=thread-reply` with the triggering `messageId`. As a result, the assistant calls `message(action="send")` which resolves to the plain `chatId` (e.g. `oc_xxx`) without any topic/thread context.

In `channel-BHQ-AXGx.js`, `replyInThread` is only set to `true` when `ctx.action === "thread-reply"`:

---
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

Summary

When a Feishu group chat message triggers a group_topic-scoped session, the assistant's reply is sent as a normal group message rather than as a thread (话题) reply to the original message.

Root Cause

buildGroupChatContext() in get-reply-CfL1pJQm.js generates the system prompt:

"Normal final replies are private and are not automatically sent to this group chat. To post visible output here, use the message tool with action=send..."

For group_topic sessions, this instruction does not tell the assistant to use action=thread-reply with the triggering messageId. As a result, the assistant calls message(action="send") which resolves to the plain chatId (e.g. oc_xxx) without any topic/thread context.

In channel-BHQ-AXGx.js, replyInThread is only set to true when ctx.action === "thread-reply":

replyInThread: ctx.action === "thread-reply"

### Steps to reproduce

# Summary

When a Feishu group chat message triggers a `group_topic`-scoped session, the assistant's reply is sent as a normal group message rather than as a thread (话题) reply to the original message.

## Root Cause

`buildGroupChatContext()` in `get-reply-CfL1pJQm.js` generates the system prompt:

> "Normal final replies are private and are not automatically sent to this group chat. To post visible output here, use the message tool with **action=send**..."

For `group_topic` sessions, this instruction does not tell the assistant to use `action=thread-reply` with the triggering `messageId`. As a result, the assistant calls `message(action="send")` which resolves to the plain `chatId` (e.g. `oc_xxx`) without any topic/thread context.

In `channel-BHQ-AXGx.js`, `replyInThread` is only set to `true` when `ctx.action === "thread-reply"`:
```js
replyInThread: ctx.action === "thread-reply"

### Expected behavior

# Summary

When a Feishu group chat message triggers a `group_topic`-scoped session, the assistant's reply is sent as a normal group message rather than as a thread (话题) reply to the original message.

## Root Cause

`buildGroupChatContext()` in `get-reply-CfL1pJQm.js` generates the system prompt:

> "Normal final replies are private and are not automatically sent to this group chat. To post visible output here, use the message tool with **action=send**..."

For `group_topic` sessions, this instruction does not tell the assistant to use `action=thread-reply` with the triggering `messageId`. As a result, the assistant calls `message(action="send")` which resolves to the plain `chatId` (e.g. `oc_xxx`) without any topic/thread context.

In `channel-BHQ-AXGx.js`, `replyInThread` is only set to `true` when `ctx.action === "thread-reply"`:
```js
replyInThread: ctx.action === "thread-reply"

### Actual behavior

# Summary

When a Feishu group chat message triggers a `group_topic`-scoped session, the assistant's reply is sent as a normal group message rather than as a thread (话题) reply to the original message.

## Root Cause

`buildGroupChatContext()` in `get-reply-CfL1pJQm.js` generates the system prompt:

> "Normal final replies are private and are not automatically sent to this group chat. To post visible output here, use the message tool with **action=send**..."

For `group_topic` sessions, this instruction does not tell the assistant to use `action=thread-reply` with the triggering `messageId`. As a result, the assistant calls `message(action="send")` which resolves to the plain `chatId` (e.g. `oc_xxx`) without any topic/thread context.

In `channel-BHQ-AXGx.js`, `replyInThread` is only set to `true` when `ctx.action === "thread-reply"`:
```js
replyInThread: ctx.action === "thread-reply"

### OpenClaw version

2026.4.27

### Operating system

docker

### Install method

_No response_

### Model

claude

### Provider / routing chain

openclaw

### Additional provider/model setup details

_No response_

### Logs, screenshots, and evidence

```shell

Impact and severity

No response

Additional information

No response

extent analysis

TL;DR

Modify the buildGroupChatContext() function in get-reply-CfL1pJQm.js to include action=thread-reply with the triggering messageId for group_topic sessions.

Guidance

  • Update the system prompt in buildGroupChatContext() to instruct the assistant to use action=thread-reply with the triggering messageId for group_topic sessions.
  • Verify that replyInThread is set to true in channel-BHQ-AXGx.js when ctx.action === "thread-reply".
  • Test the updated code with a group_topic-scoped session to ensure the assistant's reply is sent as a thread reply to the original message.
  • Review the code changes to ensure they do not introduce any unintended behavior for other types of sessions.

Example

// Updated buildGroupChatContext() function
if (sessionType === 'group_topic') {
  systemPrompt = `To post visible output here, use the message tool with action=thread-reply and messageId=${triggeringMessageId}`;
}

Notes

The provided solution assumes that the triggeringMessageId is available in the buildGroupChatContext() function. If this is not the case, additional modifications may be necessary to retrieve or pass this information.

Recommendation

Apply the workaround by updating the buildGroupChatContext() function to include action=thread-reply with the triggering messageId for group_topic sessions, as this should resolve the issue without requiring an upgrade to a fixed version.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Summary

When a Feishu group chat message triggers a group_topic-scoped session, the assistant's reply is sent as a normal group message rather than as a thread (话题) reply to the original message.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: [Feishu] group_topic session: assistant uses action=send instead of thread-reply, reply not posted in topic thread [2 pull requests, 1 comments, 2 participants]