Skip to content

fix(gateway): stream consumer first message drops thread context - #13077

Closed
hrygo wants to merge 2 commits into
NousResearch:mainfrom
hrygo:fix/stream-consumer-thread-routing
Closed

fix(gateway): stream consumer first message drops thread context#13077
hrygo wants to merge 2 commits into
NousResearch:mainfrom
hrygo:fix/stream-consumer-thread-routing

Conversation

@hrygo

@hrygo hrygo commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Problem

When a user @mentions the bot inside a group topic thread (Feishu group topic / Slack thread / Telegram forum), the first streamed message chunk is sent via message.create with receive_id=chat_id (the main group) instead of being threaded into the topic. The response — including any visible thinking/reasoning — appears in the main group chat rather than the topic thread.

This is a cross-platform architecture defect in GatewayStreamConsumer that has been reported multiple times across different platforms:

Root Cause

Two bugs:

Bug 1: GatewayStreamConsumer sends first chunk without reply_to

gateway/stream_consumer.py_send_or_edit() first-message path:

# BEFORE — no reply_to passed
result = await self.adapter.send(
    chat_id=self.chat_id,
    content=text,
    metadata=self.metadata,
)

self._message_id is None on the first send, and no fallback reply_to is provided. The adapter receives reply_to=None → falls to message.create with receive_id=chat_id → message lands in main chat.

Meanwhile, the non-streaming path in base.py has always correctly passed reply_to=event.message_id. This is why short answers work fine — only streaming (long answers / tool-heavy responses) triggers the bug.

Bug 2: FeishuAdapter._send_raw_message fallback loses thread context

When message.reply fails (e.g. message withdrawn, error codes in _FEISHU_REPLY_FALLBACK_CODES) and falls back to message.create, the fallback uses receive_id=chat_id even though metadata.thread_id is available — as independently identified in #9916.

Fix (3 files)

File Change
gateway/stream_consumer.py __init__ accepts optional initial_reply_to_id; _send_or_edit passes it as reply_to on first send
gateway/platforms/feishu.py _send_raw_message fallback checks metadata.thread_id, uses receive_id_type="thread_id" instead of "chat_id"
gateway/run.py Both GatewayStreamConsumer creation sites (proxy path L8000 + local path L8575) pass initial_reply_to_id=event_message_id

Affected Platforms

Any platform using topic/thread routing:

Reproduction

  1. Create a group chat topic in Feishu (or forum topic in Telegram)
  2. @mention the bot inside the topic thread
  3. Ask something that triggers a long response or tool use (streaming)
  4. Observe: the streamed response appears in the main group chat, not in the topic thread
  5. Short non-streaming answers work correctly

Backward Compatibility

initial_reply_to_id defaults to None — no impact on existing code or platforms without thread routing.

Closes

Closes #6969
Closes #9916
Closes #7355

…tream-consumer-thread-routing

Cherry-picked commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group topics,
Slack threads, Telegram forum topics. Also fixes Feishu fallback path (reply→create)
to use thread_id instead of chat_id.
@hrygo
hrygo force-pushed the fix/stream-consumer-thread-routing branch from 2d7860a to 7554711 Compare May 9, 2026 01:25
…path

When the first streamed message exceeds the platform length limit and
gets split into chunks, _send_new_chunk was called with self._message_id
(which is None on first send), dropping thread routing entirely.

Fallback to self._initial_reply_to_id so overflow chunks land in the
correct topic/thread.

Also fix a fragile test assertion that could be silently skipped.
teknium1 pushed a commit that referenced this pull request May 10, 2026
Cherry-picked from PR #13077 commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group
topics, Slack threads, Telegram forum topics. Adds initial_reply_to_id
ctor arg to GatewayStreamConsumer, threaded through _send_or_edit and
_send_new_chunk. Also fixes Feishu _send_raw_message fallback path
(reply -> create) to use receive_id_type='thread_id' so the new message
lands in the correct topic instead of the main channel.

Authored by hrygo via PR #13077 (re-attributed from the bot-authored
salvage commit on the original branch).
@teknium1

Copy link
Copy Markdown
Contributor

Merged via salvage PR #23437 (#23437). Your two commits were cherry-picked onto current main with your authorship preserved (re-attributed from the bot-authored commit on your branch to hrygo). We added a test compat fix so the new Feishu fallback test runs in environments without the lark SDK installed, plus an AUTHOR_MAP entry. Conflict against PR #23420 (just-landed #10748 fix) was resolved by merging both fixes in the same chunk loop. Thanks for the fix — this also closes paths #6969 and #9916 as a side effect.

@teknium1 teknium1 closed this May 10, 2026
JinyuID pushed a commit to JinyuID/hermes-agent that referenced this pull request May 11, 2026
Cherry-picked from PR NousResearch#13077 commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group
topics, Slack threads, Telegram forum topics. Adds initial_reply_to_id
ctor arg to GatewayStreamConsumer, threaded through _send_or_edit and
_send_new_chunk. Also fixes Feishu _send_raw_message fallback path
(reply -> create) to use receive_id_type='thread_id' so the new message
lands in the correct topic instead of the main channel.

Authored by hrygo via PR NousResearch#13077 (re-attributed from the bot-authored
salvage commit on the original branch).
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
Cherry-picked from PR NousResearch#13077 commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group
topics, Slack threads, Telegram forum topics. Adds initial_reply_to_id
ctor arg to GatewayStreamConsumer, threaded through _send_or_edit and
_send_new_chunk. Also fixes Feishu _send_raw_message fallback path
(reply -> create) to use receive_id_type='thread_id' so the new message
lands in the correct topic instead of the main channel.

Authored by hrygo via PR NousResearch#13077 (re-attributed from the bot-authored
salvage commit on the original branch).
jsboige pushed a commit to jsboige/hermes-agent that referenced this pull request May 14, 2026
Cherry-picked from PR NousResearch#13077 commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group
topics, Slack threads, Telegram forum topics. Adds initial_reply_to_id
ctor arg to GatewayStreamConsumer, threaded through _send_or_edit and
_send_new_chunk. Also fixes Feishu _send_raw_message fallback path
(reply -> create) to use receive_id_type='thread_id' so the new message
lands in the correct topic instead of the main channel.

Authored by hrygo via PR NousResearch#13077 (re-attributed from the bot-authored
salvage commit on the original branch).
AlexFoxD pushed a commit to AlexFoxD/hermes-agent that referenced this pull request May 21, 2026
Cherry-picked from PR NousResearch#13077 commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group
topics, Slack threads, Telegram forum topics. Adds initial_reply_to_id
ctor arg to GatewayStreamConsumer, threaded through _send_or_edit and
_send_new_chunk. Also fixes Feishu _send_raw_message fallback path
(reply -> create) to use receive_id_type='thread_id' so the new message
lands in the correct topic instead of the main channel.

Authored by hrygo via PR NousResearch#13077 (re-attributed from the bot-authored
salvage commit on the original branch).
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
Cherry-picked from PR NousResearch#13077 commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group
topics, Slack threads, Telegram forum topics. Adds initial_reply_to_id
ctor arg to GatewayStreamConsumer, threaded through _send_or_edit and
_send_new_chunk. Also fixes Feishu _send_raw_message fallback path
(reply -> create) to use receive_id_type='thread_id' so the new message
lands in the correct topic instead of the main channel.

Authored by hrygo via PR NousResearch#13077 (re-attributed from the bot-authored
salvage commit on the original branch).
Seven74AI pushed a commit to Seven74AI/hermes-agent that referenced this pull request Jun 13, 2026
Cherry-picked from PR NousResearch#13077 commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group
topics, Slack threads, Telegram forum topics. Adds initial_reply_to_id
ctor arg to GatewayStreamConsumer, threaded through _send_or_edit and
_send_new_chunk. Also fixes Feishu _send_raw_message fallback path
(reply -> create) to use receive_id_type='thread_id' so the new message
lands in the correct topic instead of the main channel.

Authored by hrygo via PR NousResearch#13077 (re-attributed from the bot-authored
salvage commit on the original branch).
T02200059 pushed a commit to T02200059/hermes-agent that referenced this pull request Jun 18, 2026
Cherry-picked from PR NousResearch#13077 commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group
topics, Slack threads, Telegram forum topics. Adds initial_reply_to_id
ctor arg to GatewayStreamConsumer, threaded through _send_or_edit and
_send_new_chunk. Also fixes Feishu _send_raw_message fallback path
(reply -> create) to use receive_id_type='thread_id' so the new message
lands in the correct topic instead of the main channel.

Authored by hrygo via PR NousResearch#13077 (re-attributed from the bot-authored
salvage commit on the original branch).
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
Cherry-picked from PR NousResearch#13077 commits:
- 5500c7d8 fix(gateway): stream consumer first message drops thread context
- e84403b9 test(gateway): add regression tests for stream consumer thread routing

Fixes: Streaming first message drops thread/topic context in Feishu group
topics, Slack threads, Telegram forum topics. Adds initial_reply_to_id
ctor arg to GatewayStreamConsumer, threaded through _send_or_edit and
_send_new_chunk. Also fixes Feishu _send_raw_message fallback path
(reply -> create) to use receive_id_type='thread_id' so the new message
lands in the correct topic instead of the main channel.

Authored by hrygo via PR NousResearch#13077 (re-attributed from the bot-authored
salvage commit on the original branch).
DarkMagicCK added a commit to DarkMagicCK/hermes-agent that referenced this pull request Aug 20, 2026
…d receive_id

Async-delegation completions and terminal background notifications re-enter the
originating session as synthetic events with no om_ reply anchor. The Feishu
adapter's fallback branch then sent these via receive_id_type=thread_id on the
create-message API, which the Feishu server rejects with
[99992402] field validation failed — thread_id is not a valid receive_id_type
(only open_id/union_id/user_id/email/chat_id are). A message can only land in
a topic through the reply API (reply_in_thread=true) against a real om_ id.

The broken branch was added in NousResearch#13077 (ff14666) and its regression test was a
pure mock that only asserted the request was shaped as thread_id, never
exercising the real API — a green-mock-hides-integration-bug case.

Root fix — anchor everything on a stable om_ id threaded end-to-end:
- Feishu inbound: populate source.message_id with the topic root (om_),
  so it flows into _SESSION_MESSAGE_ID and is captured by background watchers.
- delegate_task(background=true): capture message_id before detaching onto the
  daemon worker thread (mirrors session_key capture) and carry it onto the
  completion event.
- terminal text notifications: pass reply_to=message_id for thread routing.
- _inject_watch_notification: fall back to the persisted session origin's
  message_id when the event lacks one.
- Feishu adapter: remove the illegal receive_id_type=thread_id create branch;
  fall back to a top-level chat create with a warning when no anchor is
  available (strictly better than a hard send failure, and unreachable in
  normal operation once the routing layer populates anchors).

Tests:
- Replace the test that asserted receive_id_type=thread_id (it was freezing the
  bug) with reply-API-contract assertions + a no-anchor top-level fallback case.
- Add Feishu inbound source.message_id tests (topic root + seed message).
- Add async-delegation message_id propagation tests (single, batch, default).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround platform/feishu Feishu / Lark adapter type/bug Something isn't working

Projects

None yet

5 participants