Skip to content

fix(feishu): preserve quoted reply ancestry (#67184) - #67222

Open
webtecnica wants to merge 1 commit into
NousResearch:mainfrom
webtecnica:fix/67184-feishu-quoted-reply
Open

fix(feishu): preserve quoted reply ancestry (#67184)#67222
webtecnica wants to merge 1 commit into
NousResearch:mainfrom
webtecnica:fix/67184-feishu-quoted-reply

Conversation

@webtecnica

Copy link
Copy Markdown
Contributor

What does this PR do?

Feishu quote replies currently fetch only the direct parent text. When that parent is itself a reply, short follow-ups such as "this one" or "agree" lose the original question that gives the parent its meaning.

This change follows the explicit parent_id / upper_message_id ancestry for quoted messages and supplies a bounded text chain through the existing reply_to_text field.

Related Issue

Fixes #67184.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✅ Tests (adding or improving test coverage)

Changes Made

  • plugins/platforms/feishu/adapter.py
    • Follow bounded quoted-message ancestry with the direct parent first.
    • Reuse a shared LRU message-item fetch path so text and future media context do not duplicate API calls.
    • Follow parent_id, upper_message_id, and root-only ancestry while retaining cycle protection.
    • Keep the complete reply context within the existing 500-character gateway budget.
    • Stop after six messages, on cycles, API errors, cross-chat ancestors, or explicit thread mismatches.
    • Use the adapter-owned blocking-call executor for Feishu SDK requests.
  • tests/gateway/test_feishu.py
    • Cover nested quotes, direct-parent priority, total budget, cycles, API degradation, chat boundaries, thread boundaries, and inbound propagation.

How to Test

  1. python -m pytest tests/gateway/test_feishu.py::TestFeishuFetchMessageText -q — 14 passed.
  2. python -m pytest tests/gateway/test_feishu.py -q — 173 passed, 47 skipped.
  3. python -m pytest tests/gateway/test_reply_to_injection.py -q — 6 passed.
  4. ruff check plugins/platforms/feishu/adapter.py tests/gateway/test_feishu.py — All checks passed.
  5. python -m py_compile plugins/platforms/feishu/adapter.py tests/gateway/test_feishu.py — OK.
  6. git diff --check — passed.

Follow the Feishu parent_id / upper_message_id chain for quoted
replies to preserve nested message ancestry. Direct parents come
first, ancestors follow via "[Earlier quoted message]" separator.

- Add _fetch_message_item() with shared LRU cache (128 entries) so
  text and future media context consumers do not duplicate API calls.
- Add _fetch_message_context_chain() with bounded traversal:
  max 6 messages deep, 500-char budget, cycle detection, and stops
  on API errors, chat-boundary changes, and thread mismatches.
- Reuse the adapter-owned blocking-call executor for all Feishu SDK
  requests to stay within the gateway's async model.
- Keep the existing gateway 500-character reply-context budget as
  the final transport boundary; direct non-nested replies retain
  their current behavior.

Closes NousResearch#67184
@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins platform/feishu Feishu / Lark adapter P3 Low — cosmetic, nice to have sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages duplicate This issue or pull request already exists labels Jul 19, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #66207: both implement the same bounded Feishu quoted-reply ancestry and reply-context mechanism.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the focused Feishu reply-context work. The underlying gap is present on current main: plugins/platforms/feishu/adapter.py:3257-3263 resolves one target and :4173-4204 fetches only that message.

Problems

  • plugins/platforms/feishu/adapter.py:4302 slices text without a null guard (and :4309 does the same for later ancestors). _extract_text_from_raw_content returns Optional[str] at current-main plugins/platforms/feishu/adapter.py:4206-4222; an empty or unknown quote can therefore raise TypeError during inbound processing. Please render only when text is present, while continuing traversal.
  • This duplicates open #66207, as noted in the member discussion. Its traversal places rendering inside if text, and it includes a message-item cache reuse test.

Suggested changes

  • Add an empty/unknown quote-item regression case, including a later textual ancestor.
  • Consolidate with #66207 so the selected salvage has one maintained implementation.

Automated hermes-sweeper review.

self._message_text_cache.popitem(last=False)

if not rendered:
rendered = text[:max_chars]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_extract_text_from_raw_content returns Optional[str]; for an unknown or empty quote item this slice raises TypeError (and the later text[:remaining] has the same issue). Render only inside if text, then continue ancestry traversal so a textless direct parent does not abort inbound processing.

@teknium1 teknium1 added the sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform label Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have platform/feishu Feishu / Lark adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feishu quoted replies lose nested message ancestry

3 participants