mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-08 23:06:03 +00:00
136 lines
9.1 KiB
Markdown
136 lines
9.1 KiB
Markdown
# Lark / Feishu EBA Adapter Migration Record
|
|
|
|
Status: migrated with unit coverage and partial live plugin E2E. WebSocket text reached the standalone runtime once in the LangBot organization test app, but the latest real UI image/file inbound attempts did not reach the local adapter log, so media receive is not release-complete yet.
|
|
|
|
Adapter directory: `src/langbot/pkg/platform/adapters/lark/`
|
|
|
|
## What Changed
|
|
|
|
The Lark/Feishu adapter now has an Event-Based Agents adapter package with:
|
|
|
|
- `manifest.yaml` for adapter metadata, configuration, events, common APIs, platform-specific APIs, app type, and communication mode.
|
|
- `adapter.py` for self-built/store app token handling, WebSocket long connection startup, Webhook callback handling, card feedback, streaming-card replies, and EBA dispatch.
|
|
- `event_converter.py` for native Feishu events to common EBA events.
|
|
- `message_converter.py` for Feishu text/post/image/file/audio payloads to/from common `MessageChain` components.
|
|
- `api_impl.py` for common EBA API implementations.
|
|
- `platform_api.py` for Feishu-specific `call_platform_api` actions.
|
|
|
|
The legacy `lark` adapter remains available while the EBA adapter is registered separately as `lark-eba`.
|
|
|
|
## Configuration
|
|
|
|
| Field | Required | Notes |
|
|
|-------|----------|-------|
|
|
| `app_id` | yes | Feishu/Lark application App ID. |
|
|
| `app_secret` | yes | Feishu/Lark application App Secret. |
|
|
| `bot_name` | yes | Must match the bot name so group mentions can be recognized. |
|
|
| `enable-webhook` | yes | `false` uses WebSocket long connection; `true` uses Request URL/Webhook callbacks. |
|
|
| `webhook_url` | no | Generated callback URL for Webhook mode. |
|
|
| `encrypt-key` | no | Webhook decrypt key when event encryption is enabled. |
|
|
| `enable-stream-reply` | yes | Enables streaming replies through an updating Feishu card. |
|
|
| `app_type` | no | `self` for self-built apps; `isv` for store apps. |
|
|
| `bot_added_welcome` | no | Optional group welcome message sent after bot-added events. |
|
|
|
|
## Application And Communication Modes
|
|
|
|
| Mode | Support | Implementation |
|
|
|------|---------|----------------|
|
|
| Self-built application | implemented | Uses standard app credentials and tenant token behavior from the Feishu SDK client. |
|
|
| Store application | implemented | Builds an ISV client, requests app tickets, and resolves app/tenant access tokens with per-tenant caching. |
|
|
| WebSocket long connection | implemented | Registers `im.message.receive_v1` and card-action callbacks through `lark_oapi.ws.Client`. |
|
|
| Webhook Request URL | implemented | Handles URL verification, encrypted payloads, message events, app-ticket events, bot-added events, and card-action feedback. |
|
|
|
|
## Supported Events
|
|
|
|
| Event | Support | Evidence |
|
|
|-------|---------|----------|
|
|
| `message.received` | implemented | Unit coverage for private and group native events to common EBA events. |
|
|
| `bot.invited_to_group` | implemented | Webhook bot-added event maps to common bot invite event and optional welcome send. |
|
|
| `platform.specific` | implemented | Unknown callback events are preserved as `platform.specific`. |
|
|
| `FeedbackEvent` | compatibility event | Card button feedback is still dispatched through the existing SDK `FeedbackEvent` type. |
|
|
|
|
## Receive Components
|
|
|
|
| Component | Support | Evidence |
|
|
|-----------|---------|----------|
|
|
| `Source` | supported | Unit coverage; live private text evidence. |
|
|
| `Plain` | supported | Text and post payloads convert to common text; live private text evidence. |
|
|
| `At` | supported | Feishu mentions map to common `At` with user ID and display name. |
|
|
| `AtAll` | supported | `user_id=all` maps to common `AtAll`. |
|
|
| `Image` | supported | Image payloads download through message resource API and map to common `Image`; real UI image send attempted, but not observed in local plugin evidence yet. |
|
|
| `Voice` | supported | Audio payloads download through message resource API and map to common `Voice`. |
|
|
| `File` | supported | File payloads download through message resource API and map to common `File`; real UI file send attempted, but not observed in local plugin evidence yet. |
|
|
| `Quote` | supported | Parent/thread reply lookup maps quoted content into common `Quote`. |
|
|
| `Face` | not native common mapping | Feishu emoji/stickers are not exposed as a portable common `Face` component here. |
|
|
| `Forward` | not-supported inbound | Feishu does not expose a portable structured forward event in this adapter. |
|
|
|
|
## Send Components
|
|
|
|
| Component | Support | Evidence |
|
|
|-----------|---------|----------|
|
|
| `Plain` | supported | Unit coverage; sends Feishu `text`. |
|
|
| `At` | supported | Unit coverage; sends Feishu `post` at element. |
|
|
| `AtAll` | supported | Unit coverage; sends Feishu `post` at-all element. |
|
|
| `Image` | supported | Uploads image resource and sends Feishu `image`. |
|
|
| `Voice` | supported | Uploads OPUS/audio resource and sends Feishu `audio`. |
|
|
| `File` | supported | Uploads file resource and sends Feishu `file`. |
|
|
| `Quote` | supported/fallback | Sends quote marker plus origin content. |
|
|
| `Face` | not-supported | No portable send mapping. |
|
|
| `Forward` | flattened fallback | Flattens forward nodes into text/media messages. |
|
|
|
|
## Common APIs
|
|
|
|
| API | Support | Notes |
|
|
|-----|---------|-------|
|
|
| `send_message` | supported | Supports private/open_id and group/chat_id targets; live plugin outbound component sweep produced visible Feishu messages. |
|
|
| `reply_message` | supported | Replies to the source Feishu message; fixed to recover the native Feishu message ID from legacy-wrapped source events. |
|
|
| `get_message` | cache-backed/API-backed | Returns cached inbound event where possible and converts uncached Feishu message API items into common `MessageReceivedEvent`. |
|
|
| `get_group_info` | supported | Uses cached group or Feishu chat metadata. |
|
|
| `get_group_member_info` | limited | Uses cached user data when available. |
|
|
| `get_user_info` | limited | Uses cached user data when available. |
|
|
| `get_file_url` | limited | Returns `file://` paths from downloaded inbound resources; remote Feishu resource download uses platform-specific API params. |
|
|
| `call_platform_api` | supported | See below. |
|
|
|
|
## Platform-Specific APIs
|
|
|
|
| Action | Support | Evidence |
|
|
|--------|---------|----------|
|
|
| `check_tenant_access_token` | supported | Unit coverage. |
|
|
| `refresh_app_access_token` | supported | Store-app token path implemented. |
|
|
| `refresh_tenant_access_token` | supported | Store-app tenant token path implemented. |
|
|
| `get_chat` | supported | Feishu chat metadata API wrapper. |
|
|
| `get_message` | supported | Feishu message API wrapper with JSON-safe return values for plugin calls. |
|
|
| `get_message_resource` | supported | Feishu message resource download wrapper. |
|
|
|
|
## End-to-End Evidence
|
|
|
|
Current code-level evidence:
|
|
|
|
- `tests/unit_tests/platform/test_lark_eba_adapter.py`
|
|
- `PYTHONPATH=../langbot-plugin-sdk/src uv run pytest tests/unit_tests/platform/test_lark_eba_adapter.py -q`
|
|
|
|
Live evidence collected on May 11, 2026:
|
|
|
|
- Standalone runtime: `uv run lbp rt --ws-control-port 5400 --ws-debug-port 5401 --skip-deps-check`
|
|
- LangBot: `uv run main.py --standalone-runtime --debug`
|
|
- Plugin: `LangBot__EBAEventProbe`
|
|
- Feishu org/app: LangBot organization, `LangBotDev` private chat.
|
|
- Observed plugin JSONL: one private `MessageReceived` event with `Source + Plain`; plugin API probe then exercised bot discovery, bot info, `send_message`, outbound component sweep, storage/list APIs, and safe platform API calls.
|
|
- Real UI sends attempted after the fixes: private text, local file, and image/video image upload. These appeared in the Feishu client but did not append new `EBAEventProbe` records in the local JSONL during this run.
|
|
- Fixes from live testing: reply path now extracts the native Feishu `message_id` from legacy-wrapped source events; WebSocket callbacks are scheduled onto the adapter event loop instead of assuming the SDK callback has a running asyncio loop; platform API results are converted to JSON-safe values.
|
|
|
|
Live E2E items still required before marking release-complete:
|
|
|
|
- WebSocket self-built app in LangBot organization: repeat private text after callback-loop fix, plus private image/file/audio and group mention message received by `EBAEventProbe`.
|
|
- Webhook self-built app in LangBot organization: URL verification plus text/image/file message received by `EBAEventProbe`.
|
|
- Store app token path: at least token acquisition/tenant-token safe API through `call_platform_api`; full message E2E if a LangBot organization store-app fixture is available.
|
|
- Outbound component sweep: text, mention, at-all, image, file, voice where Feishu accepts the fixture, quote/fallback, and forward/fallback.
|
|
- Safe platform API sweep: token check, chat metadata, message lookup, and message resource download using real inbound IDs.
|
|
|
|
## Known Limits
|
|
|
|
- Store-app live E2E requires a real ISV app ticket/tenant installation fixture.
|
|
- Current LangBot organization WebSocket run connected successfully but did not deliver the latest UI-sent image/file attempts to local plugin evidence; this blocks release-complete media acceptance.
|
|
- Feishu native emoji/sticker semantics are not represented as common `Face`.
|
|
- Destructive org or chat mutations are not declared in this adapter.
|