Skip to content

hotfix(feishu): use emoji reaction as typing indicator#14799

Open
DeJeune wants to merge 6 commits intoCherryHQ:mainfrom
DeJeune:hotfix/feishu-typing-reaction
Open

hotfix(feishu): use emoji reaction as typing indicator#14799
DeJeune wants to merge 6 commits intoCherryHQ:mainfrom
DeJeune:hotfix/feishu-typing-reaction

Conversation

@DeJeune
Copy link
Copy Markdown
Collaborator

@DeJeune DeJeune commented May 2, 2026

What this PR does

Before this PR:

FeishuAdapter.sendTypingIndicator was a no-op because Feishu has no native
typing API. Users sending a message to a Feishu agent had no visual signal
that the bot had received their message until the streaming card or first
reply appeared, which can take several seconds.

After this PR:

sendTypingIndicator(chatId) now adds a THUMBSUP emoji reaction to the
user's most recent message in that chat (via im.messageReaction.create),
giving users immediate, in-thread feedback that the agent is processing.
The reaction is removed once we reply (sendMessage), the streaming
response finalizes (onStreamComplete), the stream errors
(onStreamError), or the adapter disconnects. The same reaction is reused
idempotently across the 4 s typing-refresh interval, so no duplicate API
calls are made for one user message.

Fixes #

Why we need it and why it was done in this way

Feishu has no native typing/presence API for bots, so the only in-channel
signal we can produce before responding is a message reaction. Reacting to
the user's last message is the closest analog to "typing…" in Feishu's UX:
it appears in the same thread, costs one cheap API call, and is easy to
clean up.

The following tradeoffs were made:

  • Used THUMBSUP as the emoji. It's broadly supported across Feishu/Lark
    tenants. The constant is documented and easy to swap.
  • Tracked the latest user message_id per chat in memory. This is
    acceptable because reactions are only meaningful for the most recent
    user turn, and adapters are recreated on disconnect.
  • Did not extend the abstract sendTypingIndicator(chatId) signature with
    a messageId, to avoid touching every other channel adapter.

The following alternatives were considered:

  • Sending a placeholder text message ("…thinking") — too noisy, would
    require deletion via a separate API and clutter the chat.
  • Doing nothing (status quo) — leaves users without any acknowledgement
    for several seconds.

Links to places where the discussion took place:

Breaking changes

None.

Special notes for your reviewer

  • Cleanup is wired into all completion paths (sendMessage,
    onStreamComplete, onStreamError, performDisconnect) so the
    reaction does not linger after a reply.
  • Failures of the reaction create/delete API calls are swallowed at
    debug level — typing feedback is best-effort and must never break
    message handling.
  • Targets main per the v2 code-freeze policy because this is a
    user-visible UX gap fix scoped to one adapter, with no refactoring.

Checklist

  • PR: The PR description is expressive enough and will help future contributors
  • Code: Write code that humans can understand and Keep it simple
  • Refactor: You have left the code cleaner than you found it (Boy Scout Rule)
  • Upgrade: Impact of this change on upgrade flows was considered and addressed if required
  • Documentation: A user-guide update was considered and is present (link) or not required. Check this only when the PR introduces or changes a user-facing feature or behavior.
  • Self-review: I have reviewed my own code before requesting review from others

Release note

Feishu agent channel: show a 👍 reaction on your latest message while the
bot is processing, replacing the previous no-op typing indicator.

Feishu has no native typing API. React to the user's latest message with
THUMBSUP so users get visible feedback that the agent is processing,
and remove the reaction once we reply (or on stream end / disconnect).

Signed-off-by: suyao <sy20010504@gmail.com>
@ousugo
Copy link
Copy Markdown
Collaborator

ousugo commented May 4, 2026

Note

This comment was translated by Claude.

Referring to openclaw, wouldn't it be more appropriate to use the "typing keyboard" emoji? The 👍 reaction is more commonly used after a reply is completed.

image
Original Content

参照 openclaw,使用敲键盘这个 emoji 是不是更合适, 👍 更多时候用于回复完成后的 reaction

image

DeJeune added 5 commits May 6, 2026 10:21
Replace single THUMBSUP reaction with a 3-stage status indicator:
  - INHALE while processing (set on sendTypingIndicator)
  - OK_HAND when the reply is delivered (sendMessage / onStreamComplete)
  - CRY when the stream errors (onStreamError)

Transitions only fire when an active typing reaction exists, so bare
sendMessage calls (e.g. /new ack) don't get a stray DONE reaction.

Signed-off-by: suyao <sy20010504@gmail.com>
Feishu's reaction API rejected INHALE and OK_HAND with HTTP 400
"reaction type is invalid". Switch to documented emoji_type values:
THINKING (🤔) for processing and OK (👌) for done. CRY for error
was already valid.

Signed-off-by: suyao <sy20010504@gmail.com>
Switch to Feishu's native (camelCase) reactions for clearer semantics:
Typing for processing, LGTM for done. CRY remains for error since
Feishu has no native error sticker.

Signed-off-by: suyao <sy20010504@gmail.com>
Changed the reaction type used in FeishuAdapter from 'LGTM' to 'OK' for consistency with Feishu's native emoji types. This aligns with the recent updates to use valid emoji types for reactions.

Signed-off-by: suyao <sy20010504@gmail.com>
When the LLM errors before producing any text, no streaming card is
created, so the previous onStreamError() only swapped the reaction to
CRY and otherwise stayed silent — the user saw no error message in
the chat.

Extract sendRawMessage() (chunked send without reaction transitions)
and call it from onStreamError() in the no-controller branch so the
error is always delivered to the chat.

Signed-off-by: suyao <sy20010504@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants