feat: add Feishu/Lark connector with webhook event ingestion#2828
feat: add Feishu/Lark connector with webhook event ingestion#2828joezhoujinjing wants to merge 7 commits intodevelopfrom
Conversation
Implement Nexus Feishu connector (Tasks #82-84): - FeishuConnectorBackend with dual auth (bot + user OAuth) - VFS mount at /mnt/feishu/ with groups/ and p2p/ structure - Read (list_dir, read_content as YAML) and write (send_message) support - Webhook router at POST /api/v2/webhooks/feishu for event ingestion - Event mapping: message.receive -> FILE_WRITE, bot.added/deleted -> DIR_CREATE/DELETE - lark-oapi SDK integration with retry/rate-limiting Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
joezhoujinjing
left a comment
There was a problem hiding this comment.
Technical Lead Review: Real-Time Cache Invalidation Strategy
The implementation correctly follows the 'Proxy-with-Cache' philosophy, but there is a consistency gap between the webhook ingestion and the VFS read path.
Problem:
The router publishes events, but the is currently unaware of these events. This means an agent reading a chat file might see stale data from the even after a new message has arrived via webhook.
Requested Solution:
Please implement a Cache Invalidation Loop:
- Subscribe: The should subscribe to events matching its mount prefix.
- Invalidate: When an event is received for a chat path (e.g., ), the backend should call .
- Consistency: This ensures the next call bypasses the stale cache and fetches the latest state from the Feishu SSOT.
This closes the loop between 'Real-Time Events' and 'Filesystem Reads,' ensuring our AI agents always operate on the most current reality.
joezhoujinjing
left a comment
There was a problem hiding this comment.
Technical Lead Review: Real-Time Cache Invalidation Strategy
The implementation correctly follows the 'Proxy-with-Cache' philosophy, but there is a consistency gap between the webhook ingestion and the VFS read path.
Problem:
The feishu_webhook router publishes FILE_WRITE events, but the FeishuConnectorBackend is currently unaware of these events. This means an agent reading a chat file might see stale data from the CacheConnectorMixin even after a new message has arrived via webhook.
Requested Solution:
Please implement a Cache Invalidation Loop:
- Subscribe: The
FeishuConnectorBackendshould subscribe toFILE_WRITEevents matching its mount prefix. - Invalidate: When an event is received for a chat path (e.g.,
/mnt/feishu/groups/{id}.yaml), the backend should callself._invalidate_cache(path). - Consistency: This ensures the next
read_contentcall bypasses the stale cache and fetches the latest state from the Feishu SSOT.
This closes the loop between 'Real-Time Events' and 'Filesystem Reads,' ensuring our AI agents always operate on the most current reality.
When a Feishu webhook event arrives (e.g. new message), the connector's cached YAML for that chat is invalidated so the next read_content() fetches fresh data from the Feishu API instead of serving stale cache. Implementation: - Webhook router: register_cache_invalidator() callback registry - Webhook handler: calls all registered invalidators after publishing FileEvent - Connector: handle_event() strips mount prefix and calls _invalidate_cache() - Connector registers itself with webhook on init Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
joezhoujinjing
left a comment
There was a problem hiding this comment.
Technical Lead Refactor: Semantic Prefix & Hybrid Naming Strategy
After architectural review, we are shifting the Feishu VFS structure to a more robust and semantically clear model. Please refactor the implementation with the following changes:
- New Prefix: Change the mount prefix from
/mnt/feishu/to/chat/feishu/. This aligns with our 'Unified Messaging OS' philosophy. - Hybrid Naming Scheme: Filenames must use the pattern
{Name} [{ID}].yaml(e.g.,General [oc_123].yaml).- Requirement:
list_dirmust append the ID in brackets. - Requirement:
read_contentandwrite_contentmust parse the ID from the brackets to ensure persistent resolution even if the chat is renamed.
- Requirement:
- Webhook Alignment: Update the
feishu_webhook.pyrouter to map inbound events to the new/chat/feishu/paths.
This change ensures that AI agent 'links' to these files remain stable over time and that the filesystem remains human-readable.
Per tech lead review:
1. Mount prefix: /mnt/feishu/ -> /chat/feishu/ (Unified Messaging OS)
2. Hybrid filenames: "{Name} [{chat_id}].yaml" (e.g. "General [oc_123].yaml")
- list_dir appends ID in brackets for human-readable + stable links
- read_content/write_content parse chat_id from brackets for API resolution
- Chat renames don't break agent file references
3. Webhook paths updated to /chat/feishu/
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
P2P bot conversations are not returned by Feishu's List Chats API.
This adds a P2P registry populated from webhook events:
- _discover_p2p_chat() resolves peer name via get_chat_members()
- list_dir("p2p") returns discovered P2P chats with hybrid naming
- New utils: send_p2p_message(), get_chat_members(), chat_mode in get_chat_info()
- Fix import paths for current branch module structure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add FeishuEventTranslator (events.py): single source of truth for Feishu event -> FileEvent mapping, used by both webhook and WS worker - Add FeishuWebSocketWorker (ws_worker.py): persistent long connection via lark_oapi.ws.Client, zero-config (no public URL needed) - Refactor webhook router to use shared translate_feishu_event() - Auto-start WS worker in server lifespan if credentials found (UserSecretsService -> env var fallback) - Graceful shutdown on server stop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When debug_echo=True, the WS worker replies to incoming messages with the VFS path they were mapped to, e.g. "[nexus-echo] /chat/feishu/p2p/oc_xxx.yaml". Useful for E2E debugging without running the full Nexus server. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…gestion Delete feishu_webhook.py and its registration in fastapi_server.py. Update connector cache invalidation to use ws_worker directly. Clean up all webhook references in comments and docstrings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
FeishuConnectorBackend) with dual auth model (bot tenant_access_token + user OAuth viaOAuthConnectorMixin)POST /api/v2/webhooks/feishufor inbound event ingestion with challenge verification and EventBus publishinglark-oapidependency)Details
Connector (Task #82 + #84):
/mnt/feishu/groups/{name}.yamland/mnt/feishu/p2p/{name}.yamllist_dirfetches chats from Feishu API,read_contentreturns messages as YAML,write_contentsends messages via APImsg_type: text+content: {text: "hello"}CacheConnectorMixinWebhook (Task #83):
im.message.receive_v1→FILE_WRITE,im.chat.member.bot.added_v1→DIR_CREATE,im.chat.member.bot.deleted_v1→DIR_DELETEFileEventto EventBus for downstream processingTest plan
list_chats— 11 chats returned from real Feishu workspacelist_messages_from_chat— messages fetched from real chatsend_message— message delivered to Feishu grouplist_dir,read_content,write_contentflow🤖 Generated with Claude Code