Skip to content

feat(feishu): implement Feishu typing indicator via reactions - #7235

Closed
simiwe wants to merge 4 commits into
NousResearch:mainfrom
simiwe:feat/feishu-typing-indicator-slim
Closed

feat(feishu): implement Feishu typing indicator via reactions#7235
simiwe wants to merge 4 commits into
NousResearch:mainfrom
simiwe:feat/feishu-typing-indicator-slim

Conversation

@simiwe

@simiwe simiwe commented Apr 10, 2026

Copy link
Copy Markdown

What does this PR do?

Implements a visual typing indicator for the Feishu platform by repurposing message reactions.

Feishu does not provide a native typing API. The base adapter's _keep_typing loop calls send_typing() periodically while a response is being generated, and the processing path calls stop_typing() when the response finishes. In FeishuAdapter, those hooks were effectively no-ops, so Feishu users had no visual feedback that their message was being processed.

This patch adds a minimal reaction-based implementation for Feishu. When processing starts, the adapter adds a Typing reaction to the user's inbound message and stores the returned reaction_id. When processing completes, it deletes that tracked reaction by ID. The patch also records the source message_id only for real inbound message events, so synthetic reaction/card events do not overwrite the typing target.

Related Issue

No existing issue — this is a gap in the Feishu adapter confirmed through production testing.

This PR is the slimmed-down resubmission of #6890. It keeps the same core reaction-tracking approach, but removes the extra env/config surface and narrows the tests to the minimal typing lifecycle and inbound-message tracking behavior.

Related upstream context:

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

Changes Made

  • gateway/platforms/feishu.py

    • add _typing_state to track the source message_id and created reaction_id
    • implement send_typing() by creating a Typing reaction on the tracked inbound message
    • implement stop_typing() by deleting the tracked reaction and clearing state
    • update _handle_message_with_guards() so only real inbound messages seed typing state
  • tests/gateway/test_feishu.py

    • add a focused lifecycle test covering create-and-delete behavior on the source message
    • add a guard test ensuring synthetic events do not overwrite the tracked inbound message

How to Test

  1. Send a message to the bot in Feishu.
  2. Observe a Typing reaction appear on the inbound message while the agent is processing.
  3. When the agent replies, observe that the Typing reaction is removed.
  4. Run:
    • python -m pytest tests/gateway/test_feishu.py -v -o addopts=
    • python -m pytest tests/gateway/test_feishu.py -k "typing or guards or ack_reaction" -v -o addopts=
    • python -m py_compile gateway/platforms/feishu.py tests/gateway/test_feishu.py

Checklist

  • My commit messages follow the repository's conventional style
  • I searched for existing PRs to make sure this is not a duplicate
  • This PR contains only changes related to the Feishu typing indicator
  • I added tests for the changed behavior
  • I ran the targeted Feishu test coverage listed above

Design Notes

Why reactions?
Feishu's bot API does not expose a native typing endpoint. Reactions are the available in-product feedback mechanism for a bot message workflow.

Why track reaction_id?
Deleting the exact created reaction is simpler and more reliable than listing reactions and trying to rediscover the right entry later.

Why guard against synthetic events?
Feishu reaction and card callbacks are routed as synthetic events in the adapter. Those events should not change the source message used by the typing lifecycle.

@simiwe
simiwe force-pushed the feat/feishu-typing-indicator-slim branch from fad57db to d8f1e2a Compare April 10, 2026 17:14
@simiwe simiwe changed the title Add reaction-based typing indicator for Feishu feat(feishu): implement Feishu typing indicator via reactions Apr 10, 2026
simiwe added 3 commits April 16, 2026 17:00
Resolve conflicts:
- __init__: keep both _typing_state and _pending_processing_reactions
- _handle_message_with_guards: keep typing state tracking, remove obsolete
  _add_ack_reaction call (replaced by on_processing_start hook)

Adapt to upstream's new processing-reaction hooks:
- Refactor send_typing/stop_typing to reuse upstream _add_reaction/_remove_reaction
- Override on_processing_start as no-op (typing handled by send_typing via
  _keep_typing loop, preventing duplicate Typing reactions)
- Override on_processing_complete to only add CrossMark on failure
- Update tests to match new hook semantics
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery platform/feishu Feishu / Lark adapter labels Apr 29, 2026
@teknium1

Copy link
Copy Markdown
Contributor

This looks implemented on current main by the newer Feishu processing-reaction lifecycle.

Automated hermes-sweeper review evidence:

  • gateway/platforms/feishu.py:233 defines the Feishu processing reaction behavior: Typing for start, no success badge because the reply is the success signal.
  • gateway/platforms/feishu.py:1473 caches created reaction IDs by message_id, so the exact Feishu reaction can be deleted later.
  • gateway/platforms/feishu.py:3029 adds the Typing reaction in on_processing_start() and stores the returned reaction_id.
  • gateway/platforms/feishu.py:3039 removes the cached reaction in on_processing_complete() and only adds CrossMark for failures.
  • gateway/platforms/base.py:4085 and gateway/platforms/base.py:4388 show those hooks are called around the actual message-processing path.
  • tests/gateway/test_feishu.py:3632 covers the lifecycle: start, success removal, failure replacement, cancellation, delete-failure handling, and cache bounds.

The implementation shape differs from this PR's send_typing() / stop_typing() approach, but the requested Feishu visual typing indicator via reactions is present on main. The relevant implementation blames to 413990c94537e9c9da973bb21a6afcd332400b91 and is contained in release tag v2026.5.16.

@teknium1 teknium1 closed this Jun 10, 2026
@teknium1 teknium1 added the sweeper:implemented-on-main Sweeper: behavior already present on current main label Jun 10, 2026
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 P3 Low — cosmetic, nice to have platform/feishu Feishu / Lark adapter sweeper:implemented-on-main Sweeper: behavior already present on current main type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants