Skip to content

fix(feishu): WebSocket watchdog + approval card PATCH + markdown table rendering#10801

Open
bugmaker2 wants to merge 2 commits into
NousResearch:mainfrom
bugmaker2:fix/feishu-ws-approval
Open

fix(feishu): WebSocket watchdog + approval card PATCH + markdown table rendering#10801
bugmaker2 wants to merge 2 commits into
NousResearch:mainfrom
bugmaker2:fix/feishu-ws-approval

Conversation

@bugmaker2

Copy link
Copy Markdown

What does this PR do?

Three related Feishu fixes:

  1. WebSocket watchdog (fixes Feishu/Lark WebSocket drops lead to Zombie Gateway Process without auto-recovery #10616): When the lark-oapi WebSocket client's message loop exits due to ping timeout or unrecoverable error, the FeishuAdapter sets _ws_stopped = True. A new GatewayRunner._feishu_ws_watchdog() task monitors this flag and raises SystemExit(1) so systemd (or any supervisor with Restart=always) can respawn the gateway. This prevents zombie gateway processes that appear "running" but accept no messages.

  2. Approval card PATCH API (fixes Feishu command approval card buttons fail with error code 200340 #10251): The existing _update_approval_card() used im.v1.message.update (PUT) which replaces the entire message and strips interactive elements. Switched to im.v1.message.patch (PATCH) per Feishu API requirements for interactive card updates. Error 200340 was observed when using PUT.

  3. Markdown table rendering (fixes [Feishu] Markdown tables not rendering in Feishu messages #9549, fix(feishu): markdown tables not rendering as interactive cards — simplify _should_send_as_card() trigger condition #9536, [Feishu Bug] Markdown source code displayed instead of rendered card format #7022): Feishu post md elements do not support markdown table syntax. Content containing table rows (| --- | separator) is now routed to interactive card format with tag: markdown elements. Also fixed excessive markdown escaping — Feishu post md elements expect raw markdown; pre-escaping special characters caused bold/italic/code to display literally.

Related Issue

Fixes #10616 (WS watchdog)
Fixes #10251 (approval card PATCH)
Fixes #9549, #9536 (markdown tables)

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • gateway/platforms/feishu.py: Added _ws_stopped flag to FeishuAdapter, WS watchdog signaling in _run_official_feishu_ws_client, PatchMessageRequest/PatchMessageRequestBody imports, _patch_approval_card() method using PATCH API, _build_markdown_card_payload() for card format, _should_send_as_card() for table detection, removed excessive _escape_markdown_text() calls from post rendering
  • gateway/run.py: Added _feishu_ws_watchdog() async task to GatewayRunner, started in start()
  • tests/gateway/test_feishu.py: Added TestFeishuWsWatchdogFlag, TestFeishuRunOfficialWsClientWatchdog, and TestAdapterBehavior test methods for table/card markdown detection

How to Test

  1. Start Feishu gateway in WebSocket mode
  2. Trigger WS ping timeout (e.g., disconnect network temporarily) — verify process exits with code 1
  3. Send an approval card command and click approve/deny — verify card updates without error 200340
  4. Send a message containing a markdown table — verify it renders as an interactive card
  5. Run: python -m pytest tests/gateway/test_feishu.py -q -k "ws_watchdog or should_send_as_card" → 3 passed

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(feishu):)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/gateway/test_feishu.py -q — 103 passed, 16 skipped, 2 failed (lark-oapi optional dep not installed in test env)
  • I've added tests for my changes (new tests for WS watchdog and markdown detection)
  • I've tested on macOS Python 3.11

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A (no user-facing behavior change beyond fixing bugs)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-rm impact (Windows, macOS) per the compatibility guide — N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

bugmaker2 and others added 2 commits April 16, 2026 13:53
…r card updates

WebSocket watchdog (Bug #65/10616):
- Added _ws_stopped flag to FeishuAdapter.__init__
- Modified _run_official_feishu_ws_client to set _ws_stopped=True when the
  lark-oapi WS client loop exits (ping timeout or unrecoverable error)
- Added _feishu_ws_watchdog task in GatewayRunner that monitors _ws_stopped
  and raises SystemExit(1) so systemd can restart the process

Approval card PATCH (Bug #66/10251):
- Added PatchMessageRequest/PatchMessageRequestBody SDK imports
- Added _build_patch_message_body and _build_patch_message_request builders
- Added _patch_approval_card method that calls PATCH /im/v1/messages/{id}
  (instead of PUT) per Feishu API requirements for interactive cards
- Updated _resolve_approval to call _patch_approval_card after resolving

Also fixed (from merged markdown-fixer branch):
- _build_outbound_payload: check _should_send_as_card before _MARKDOWN_HINT_RE
  so tables and code-heavy content always route to card format
- _should_send_as_card: use multiline regex to count only opening fence lines
  (not closing fences), avoiding false positives from table separator rows

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…s_card() for tables

- Remove _escape_markdown_text() calls from post rendering pipeline
  (_render_text_element, link labels, @-mentions, _render_nested_post).
  Feishu post "md" elements expect raw markdown; pre-escaping special
  characters like **, *, ` caused them to display literally.
- Tables and code-heavy content (3+ code blocks) are routed to
  interactive card format via _should_send_as_card(), since Feishu
  post "md" elements do not support table syntax.
- _build_markdown_card_payload() creates card payloads with
  "tag: markdown" elements for full markdown support.
- _TABLE_RE detects markdown table separator rows for card routing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@liangshuo-1

Copy link
Copy Markdown

From my perspective, the existing callback response via P2CardActionTriggerResponse + CallBackCard already updates the card on button click — the only reason other chat members don't see the update
is that the original card config is missing "update_multi": true. I think we could simplify this by just adding that config field:

"config": {"wide_screen_mode": True, "update_multi": True},

Also worth noting that the extra PATCH call might race with the callback update.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists platform/feishu Feishu / Lark adapter comp/gateway Gateway runner, session dispatch, delivery labels Apr 25, 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 P2 Medium — degraded but workaround exists platform/feishu Feishu / Lark adapter type/bug Something isn't working

Projects

None yet

3 participants