Skip to main content

Overview

FeishuChannelExtension bridges inbound messages from a Feishu (Lark) bot into the VeADK Runner.
This page treats Feishu as an inbound message channel: messages from Feishu users trigger the agent. To let the agent call Feishu capabilities, see Feishu tools.
It listens for the bot’s message events and maps Feishu’s session identity onto VeADK: the message sender becomes the Runner’s user identity, and the thread the message belongs to becomes the session identity; when there is no thread, it falls back to the current group or direct chat as the session. In 1.0.5 it extracts text from plain messages, interactive cards, and merged-forward messages and supports the synchronous Channel SDK lifecycle.
Thread history and quoted-message retrieval are enabled by default. The extension reads related Feishu messages and sends their content to the model. If the application uses sessions, long-term memory, or logging, the content may also be retained under those policies. Before enabling the bot, confirm that message scopes, model processing, and retention meet your requirements. Disable include_thread_history and include_parent_message when this context is not required.
When an incoming message belongs to a Feishu thread or is a reply, the extension automatically fetches the thread history or the quoted parent message and prepends that context to the user message before forwarding it to the agent. See Thread history and quoted messages.

Environment & prerequisites

Installation:
If you only want this capability, install it on its own:
Environment variables:
  • TOOL_FEISHU_CHANNEL_APP_ID
  • TOOL_FEISHU_CHANNEL_APP_SECRET
  • TOOL_FEISHU_CHANNEL_TRANSPORT: defaults to ws
  • TOOL_FEISHU_CHANNEL_STREAMING: whether to enable streaming output, defaults to false
  • TOOL_FEISHU_CHANNEL_REACTIONS: whether to reply with a “received” reaction on incoming messages, defaults to false
  • TOOL_FEISHU_CHANNEL_RECONNECT_INTERVAL: seconds to wait before reconnecting after the WebSocket disconnects, defaults to 3
  • TOOL_FEISHU_CHANNEL_DRAIN_TIMEOUT: maximum seconds to wait for already-received messages to finish during a graceful shutdown, defaults to 300
Or configure in config.yaml:
config.yaml

Usage

examples/channel/feishu_bot.py

Graceful shutdown

FeishuChannelExtension exposes dedicated lifecycle methods to manage the WebSocket connection from ASGI application (FastAPI, Starlette) startup and shutdown hooks, so that rolling updates or process exits do not drop in-flight Feishu messages. Shutdown runs in two steps: first the WebSocket is closed so no new messages are accepted (Feishu re-routes new events to another instance that still holds a connection), then already-received messages are allowed to finish replying. Replies are sent over the Feishu OpenAPI HTTP client, which does not depend on the WebSocket, so messages received before shutdown still reply normally.
Long-connection scripts that only call connect() directly do not need start() / shutdown(); this is fine for simple scripts where draining messages on exit is unnecessary. Use start() and shutdown() only when hosting the channel inside an ASGI service that needs graceful shutdown.

Usage example

Call start() and shutdown() from the ASGI app’s startup and shutdown hooks:
examples/channel/feishu_asgi.py

Methods

shutdown() waits for in-flight messages to finish. If message processing takes longer than drain_timeout, unfinished tasks are cancelled. In production, tune TOOL_FEISHU_CHANNEL_DRAIN_TIMEOUT to your agent’s average response time so that normal replies are not interrupted.

Environment variables

Parameters

Thread history and quoted messages

When an incoming message comes from a Feishu thread or is a reply, the extension fetches the relevant context and prepends it to the user message before forwarding it to the agent:
  • Thread history: when the message belongs to a thread, the extension fetches the thread’s history ordered oldest-first (up to thread_history_limit messages, excluding the current message) and prepends it as thread context.
  • Quoted message: when the message is a reply but does not belong to a thread, the extension fetches the quoted parent message; if the parent cannot be fetched, it falls back to the root message of the reply chain and prepends it as quoted context.
Thread history takes precedence over quoted messages: when a thread identifier is present, only the thread history is attached and the parent message is not fetched separately. Fetched message content is rendered back to readable text, covering text, rich-text (post), interactive card, and merged-forward messages.
Fetching thread history and quoted messages requires calling Feishu OpenAPI message endpoints, so app_id and app_secret must be configured (constructor parameters, or the TOOL_FEISHU_CHANNEL_APP_ID / TOOL_FEISHU_CHANNEL_APP_SECRET environment variables, falling back to TOOL_LARK_ENDPOINT / TOOL_LARK_API_KEY). When credentials are not configured the capability is skipped silently without raising an error.

Usage example

Save and configure the feishu_bot.py example above, then create the following file in the same directory:
examples/channel/feishu_bot_thread.py
Disable the capability so the extension forwards only the current message text:
examples/channel/feishu_bot_plain.py

Notes

  • The Feishu WebSocket long-connection mode is used by default, so as long as the bot has subscribed to message events, you can start the connection directly.
  • Replies are sent as replies to the original message by default, keeping VeADK output attached to the current Feishu message thread.
  • Override the default identity mapping via session_id_factory and user_id_factory.
  • connect() and disconnect() support both async clients and synchronous Channel SDK clients exposing start() / stop().
  • When streaming output is enabled, reply content is concatenated directly from delta chunks and is no longer corrupted or truncated by the dedup heuristic.
Last modified on September 19, 2026