Skip to content

fix(feishu): fall back to post mode over table limit - #136382

Merged
vincentkoc merged 4 commits into
openclaw:mainfrom
ltspace:fix/feishu-card-table-limit-rescue
Sep 6, 2026
Merged

vincentkoc merged 4 commits into
openclaw:mainfrom
ltspace:fix/feishu-card-table-limit-rescue

Conversation

@ltspace

@ltspace ltspace commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

What problem this solves

Feishu rejects static interactive cards containing more than five table components with error 11310. OpenClaw could still route generated Markdown and presentation cards with six or more parsed tables to that rejected path, leaving users without the reply.

Closes #43690.

What changed

  • Count GFM tables with the existing Markdown parser instead of pipe/string heuristics.
  • Keep static cards at five tables or fewer.
  • Route over-limit generated cards through the existing post fallback in outbound text, presentation actions, normal replies, failed-stream recovery, and CardKit startup backoff.
  • Preserve the existing structured-card fallback for unrelated concurrent streaming handoffs.
  • Leave active CardKit streaming and caller-supplied native cards unchanged.
  • Cover pipe-less/aligned tables, fenced code, multi-element cards, HTML font wrappers, and six-table CardKit startup failure.

Production diff: +94/-24 (+70 net); test diff: +488/-1 (+487 net).

Attribution

This is a current-main rescue and rework of the original implementation in #86901 by name5566. The first two commits retain name5566 <name5566@gmail.com> as the Git author, with ltspace as the GitHub-linked committer. The review follow-up is authored and committed by ltspace.

User impact

A response with up to five Markdown tables remains an interactive card. A response with six or more tables is delivered as a Feishu post instead of failing at the provider boundary, including when CardKit startup fails.

Evidence

  • Focused Feishu routing suites: 616 tests passed across presentation-card, outbound, channel, and reply-dispatcher.
  • Review follow-up: all 182 reply-dispatcher tests passed, including six-table CardKit startup failure and existing concurrent handoff cases.
  • pnpm tsgo:extensions
  • pnpm exec oxfmt --check on changed files
  • pnpm exec oxlint on changed files
  • Live Feishu API verification from this branch:
    • 5 tables -> interactive, accepted as om_x100b66b78c862cacb1b71ffd5af9070
    • 6 tables -> post, accepted as om_x100b66b78c9324a0b1b499d6025584e

@clawsweeper

clawsweeper Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@openclaw-barnacle openclaw-barnacle Bot added channel: feishu Channel integration: feishu size: M labels Sep 2, 2026
@clawsweeper clawsweeper Bot added P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Sep 2, 2026
@clawsweeper

clawsweeper Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed September 6, 2026, 5:23 PM ET / 21:23 UTC.

ClawSweeper review

What this changes

The Feishu plugin delivers generated replies exceeding five Markdown tables as posts while preserving active streaming cards and caller-supplied native cards.

Merge readiness

✅ Ready for maintainer review

This remains a useful fix for documented Feishu delivery failures that current main still permits. Both prior blockers are addressed, and the supplied live API evidence supports the fallback boundary; no new blocking defect was found.

Priority: P1
Reviewed head: 77970ceae7ece9b2fd12182b76f5bea803b11ef9

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A focused delivery repair with relevant live receipts, broad regression coverage, and both prior blockers resolved.
Proof confidence 🐚 platinum hermit (4/6) Sufficient (live_output): The captured body reports real Feishu API delivery from this branch: five-table content remains interactive and six-table content succeeds as a post, matching the changed outbound routing. Linked provider observations support preserving CardKit streaming; recovery tests are supplemental.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (live_output): The captured body reports real Feishu API delivery from this branch: five-table content remains interactive and six-table content succeeds as a post, matching the changed outbound routing. Linked provider observations support preserving CardKit streaming; recovery tests are supplemental.
Evidence reviewed 9 items Current main still permits the failure: At fetched main, outbound card selection depends on renderMode and Markdown detection without a table ceiling; generated presentation cards only check the byte/element envelope.
Latest release retains unguarded routing: The supplied latest release, v2026.9.2, also selects outbound cards without checking table count at line 323. This is not already-shipped cleanup.
Introduced production boundary: The pinned merge-base-to-head diff adds parser-backed table checks to outbound and generated presentation cards. Native cards retain their existing envelope validation and bypass the new generated-card restriction.
Findings None None.
Security None None.

How this fits together

The Feishu plugin turns agent replies and message actions into cards or rich-text posts. Its rendering decisions feed the Feishu API and determine whether users receive the reply.

flowchart TD
  A[Agent replies and message actions] --> B[Feishu rendering]
  B --> C[Generated static card]
  B --> D[Active streaming card]
  C --> E{At most five tables}
  E -->|Yes| F[Interactive card delivery]
  E -->|No| G[Existing post fallback]
  D --> H[Streaming updates]
Loading

Before merge

None.

Agent review details

Security

None.

PR surface

Source +70, Tests +487. Total +557 across 8 files.

View PR surface stats
Area Files Added Removed Net
Source 4 94 24 +70
Tests 4 488 1 +487
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 8 582 25 +557

Review metrics

Metric Value Why it matters
Production versus regression coverage Production +70 net lines; tests +487 net lines Production growth centralizes table counting and applies it across existing delivery boundaries; regression coverage exercises those boundaries and streaming recovery.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #43690
Summary: This PR is a candidate fix for the canonical Feishu table-limit delivery report and reworks the earlier open implementation.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Technical review

Best possible solution:

Keep table-limit handling inside Feishu’s existing rendering flow, preserving valid cards and streaming while delivering otherwise rejected generated content through posts.

Do we have a high-confidence way to reproduce the issue?

Yes: a short reply containing six Markdown tables with static card rendering reaches unguarded card delivery on current main, matching the reported provider rejection. This review established the source path without executing it.

Is this the best way to solve the issue?

Yes: reusing the existing parser and post fallback is a focused repair, and separating static-card eligibility from streaming intent preserves the verified CardKit behavior.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against c1fbb4622ee2.

Labels

Label justifications:

  • P1: The linked report establishes an existing Feishu workflow that loses replies when static cards exceed the provider’s table limit.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The captured body reports real Feishu API delivery from this branch: five-table content remains interactive and six-table content succeeds as a post, matching the changed outbound routing. Linked provider observations support preserving CardKit streaming; recovery tests are supplemental.
  • proof: sufficient: Contributor real behavior proof is sufficient. The captured body reports real Feishu API delivery from this branch: five-table content remains interactive and six-table content succeeds as a post, matching the changed outbound routing. Linked provider observations support preserving CardKit streaming; recovery tests are supplemental.

Evidence

What I checked:

  • Current main still permits the failure: At fetched main, outbound card selection depends on renderMode and Markdown detection without a table ceiling; generated presentation cards only check the byte/element envelope. (extensions/feishu/src/outbound.ts:305, c1fbb4622ee2)
  • Latest release retains unguarded routing: The supplied latest release, v2026.9.2, also selects outbound cards without checking table count at line 323. This is not already-shipped cleanup. (extensions/feishu/src/outbound.ts:323, 3928bad9badf)
  • Introduced production boundary: The pinned merge-base-to-head diff adds parser-backed table checks to outbound and generated presentation cards. Native cards retain their existing envelope validation and bypass the new generated-card restriction. (extensions/feishu/src/presentation-card.ts:138, 77970ceae7ec)
  • Prior findings resolved: Current streaming eligibility uses rendering intent independently of the static ceiling. Static recovery and post-start fallback check the ceiling; added cases cover active six-table streaming, failed startup, invisible finalization, and concurrent closure. (extensions/feishu/src/reply-dispatcher.ts:1398, 77970ceae7ec)
  • Existing parser and post transport reused: The imported text-chunking SDK exports OpenClaw's Markdown parser, also used by table conversion. The existing post sender emits msg_type post and preserves account, target, reply, and thread routing. No Codex dependency contract is involved. (src/plugin-sdk/text-chunking.ts:43, 77970ceae7ec)
  • Captured live behavior evidence: The supplied PR body records branch verification against the real Feishu API: five tables accepted as interactive and six accepted as post, with separate provider message receipts. Related fix(feishu): fall back to post mode when markdown tables exceed card limit #86901 supplies additional static-card rejection, presentation fallback, font-wrapper, and CardKit streaming observations. Assessment uses the supplied snapshot, sourceRevision c86d132c0cfb0b8e331cd9da21ac043f6eebfda7df054e106d112712d7dcafd5.

Likely related people:

  • Peter Steinberger: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)
  • Eden: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)
  • vincentkoc: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (6 earlier review cycles)
  • reviewed 2026-09-02T15:17:28.294Z sha 29fb6626a48e595e4b43220fb60ba6cda9d1afd9 :: needs changes before merge. :: [P1] Gate the post-start static fallback by the table limit
  • reviewed 2026-09-02T15:34:46.712Z sha cf29a76472a14b0ab34a4ecf9ce0884236db07c5 :: needs maintainer review before merge. :: none
  • reviewed 2026-09-02T16:01:38.913Z sha d36f21ec7e44e9795eac25e02ecd02679096dc39 :: needs maintainer review before merge. :: none
  • reviewed 2026-09-06T13:11:16.102Z sha 6459551 :: blocked before merge. :: [P2] Keep the static table ceiling out of streaming eligibility
  • reviewed 2026-09-06T15:01:50.862Z sha 77970ce :: needs maintainer review before merge. :: none
  • reviewed 2026-09-06T21:11:26.039Z sha 77970ce :: needs maintainer review before merge. :: none

@ltspace
ltspace force-pushed the fix/feishu-card-table-limit-rescue branch from 29fb662 to cf29a76 Compare September 2, 2026 15:25
@ltspace

ltspace commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the CardKit-start fallback finding in cf29a76472. Over-limit content now re-applies static-card eligibility during streaming startup backoff, while unrelated concurrent streaming handoffs retain their existing card fallback. Added the six-table startup-failure regression; all 182 reply-dispatcher tests pass. @clawsweeper re-review

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Sep 2, 2026
@ltspace

ltspace commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

CI retry request: the exact-head check-dependencies job failed during runner setup, before any repository dependency checks ran. Node 24.19.0/Corepack hit Undici AssertionError [ERR_ASSERTION]: assert(!this.paused) while downloading pnpm; the other executed checks passed, and openclaw/ci-gate is red only through that failed setup job. I attempted to rerun the failed jobs, but GitHub requires repository admin rights. Could a maintainer please rerun failed jobs for run 33648650529?

name5566 and others added 3 commits September 6, 2026 21:05
Port the table-limit guard from openclaw#86901 onto the current Feishu presentation and delivery architecture. Static cards containing more than five parsed Markdown tables now use the existing post fallback; streaming CardKit and caller-supplied native cards remain unchanged.

Refs: openclaw#43690
Adapt the openclaw#86901 regression coverage to the current Feishu architecture and cover parser boundaries, outbound routing, presentation actions, reply dispatch, and streaming recovery. Also lock in the accepted font-wrapper behavior raised during the original review.

Refs: openclaw#43690
Reapply static-card eligibility while CardKit startup is backed off so over-limit Markdown falls back to post delivery. Preserve the existing structured-card fallback for unrelated concurrent streaming handoff cases.

Addresses ClawSweeper review on openclaw#136382.
@ltspace
ltspace force-pushed the fix/feishu-card-table-limit-rescue branch from d36f21e to 6459551 Compare September 6, 2026 13:05
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Sep 6, 2026
@clawsweeper clawsweeper Bot added the rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. label Sep 6, 2026
@clawsweeper clawsweeper Bot added status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Sep 6, 2026
@vincentkoc vincentkoc self-assigned this Sep 6, 2026
@vincentkoc
vincentkoc merged commit 7e21eeb into openclaw:main Sep 6, 2026
110 checks passed
@vincentkoc

Copy link
Copy Markdown
Member

Merged via squash.

vincentkoc added a commit that referenced this pull request Sep 6, 2026
* commit '294df333c58f2da104eccffc623ccb3c4d43d4d8': (1802 commits)
  fix: clear stale diagnostics after Gateway changes (#140426)
  fix: keep plugin catalogs intact after discovery timeouts (#140441)
  perf(tui): prepare session picker rows once per overlay (#140462)
  refactor(config): reuse environment substitution for write-back (#140460)
  refactor(discord): remove retired auto-presence templates (#140463)
  fix(ui): finish roster refreshes during session activity (#140459)
  fix(setup): match prepared credentials to the model provider (#140461)
  fix: keep MiniMax discovery on the selected credential (#140438)
  refactor(tests): remove unused parent context cache reset (#140456)
  fix: avoid repeated xAI OAuth refresh during discovery (#140434)
  perf(routing): reuse prepared event session targets (#140454)
  fix(media): keep deferred audio and extraction providers discoverable (#139231)
  refactor(codex): remove redundant app-server forwarding (#140451)
  fix(test): avoid false native polling timeouts (#140119)
  test(gateway): retain saved source in reload fixtures (#140453)
  fix(gateway): reduce repeated model work when listing sessions (#140414)
  fix(feishu): fall back to post mode over table limit (#136382)
  fix: use the bundle-compatible Proxyline runtime under Bun (#140411)
  refactor(trace): reuse the canonical usage counter type (#140444)
  refactor(node-host): share execution policy result fields (#140446)
  ...
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Sep 7, 2026
Route generated Feishu static cards containing more than five parsed Markdown tables through the existing post renderer while preserving supported static cards, active CardKit streams, native cards, and delivery receipts.

Apply the shared parser-backed ceiling across outbound text, presentations, message actions, ordinary replies, and failed-stream recovery.

Closes openclaw#43690

Co-authored-by: name5566 <name5566@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: feishu Channel integration: feishu P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: L status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feishu: card fails with 'table number over limit' — should fallback or render tables as images

3 participants