fix(feishu): render native presentation buttons#86017
Conversation
|
Codex review: needs maintainer review before merge. Latest ClawSweeper review: 2026-05-24 10:57 UTC / May 24, 2026, 6:57 AM ET. Workflow note: Future ClawSweeper reviews update this same comment in place. How this review workflow works
PR Surface View PR surface stats
Summary Reproducibility: yes. by source inspection: current main’s Feishu message-tool path calls a fallback-only card builder, and the existing channel test expected PR rating Rank-up moves:
What the crustacean ranks mean
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. Real behavior proof Risk before merge
Maintainer options:
Next step before merge Security Review detailsBest possible solution: Land the shared Feishu presentation-card renderer if CI stays green, with optional live Feishu proof for extra confidence on delivered card rendering and callbacks. Do we have a high-confidence way to reproduce the issue? Yes, by source inspection: current main’s Feishu message-tool path calls a fallback-only card builder, and the existing channel test expected Is this the best way to solve the issue? Yes, the proposed shape is the narrow maintainable fix: it shares the existing native Feishu presentation block mapping instead of keeping separate outbound and message-tool renderers. The only remaining proof gap is live Feishu delivery, not a code defect I can point to in the diff. Label changes:
Label justifications:
What I checked:
Likely related people:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 62b51a6295ee. |
|
ClawSweeper PR egg ✨ Hatched: 💎 rare Moonlit Test Hopper Hatch commandComment Hatchability rules:
Rarity: 💎 rare. What is this egg doing here?
|
|
@clawsweeper hatch |
|
🦞👀 I queued a comment sync for this PR. If the egg is hatchable, ClawSweeper will generate the image once and update the existing review comment. |
|
@clawsweeper automerge |
|
ClawSweeper 🐠 reef update Thanks for the work on this. ClawSweeper could not push to this branch with the permissions available, so it opened a narrow replacement PR to keep the fix swimming forward without losing the contributor trail. not your fault, just GitHub branch-permission tides. Why replacement: ClawSweeper could not update the source PR branch directly; GitHub did not grant sufficient push rights to the bot for that branch.
fish notes: model gpt-5.5, reasoning high; reviewed against 261d5a8. |

Summary
buttonsblocks as native Feishuactionelements while keeping select fallback text behaviorVerification
import { readdirSync } from 'node:fs';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
const file = readdirSync('dist').find((name) => name.startsWith('presentation-card-') && name.endsWith('.js'));
const mod = await import(pathToFileURL(path.join(process.cwd(), 'dist', file)).href);
const card = mod.t({
presentation: {
title: 'Approval',
tone: 'success',
blocks: [
{ type: 'text', text: 'Approve the request?' },
{
type: 'buttons',
buttons: [
{ label: 'Approve', value: '/approve req_1 allow-once', style: 'success' },
{ label: 'Open runbook', url: 'https://example.com/runbook', style: 'primary' }
]
}
]
}
});
console.log(JSON.stringify(card, null, 2));
PROOF
Real behavior proof
Behavior addressed: Feishu message-tool presentation buttons on channel sends were flattened into markdown fallback text instead of native interactive card actions.
Real environment tested: Local OpenClaw checkout after
pnpm build, exercising the built Feishu presentation-card renderer fromdist/with a message-tool-style presentation payload.Exact steps or command run after this patch:
Evidence after fix:
{ "schema": "2.0", "config": { "width_mode": "fill" }, "header": { "title": { "tag": "plain_text", "content": "Approval" }, "template": "green" }, "body": { "elements": [ { "tag": "markdown", "content": "Approve the request?" }, { "tag": "action", "actions": [ { "tag": "button", "text": { "tag": "plain_text", "content": "Approve" }, "type": "primary", "value": { "oc": "ocf1", "k": "quick", "a": "feishu.payload.button", "q": "/approve req_1 allow-once" } }, { "tag": "button", "text": { "tag": "plain_text", "content": "Open runbook" }, "type": "primary", "url": "https://example.com/runbook" } ] } ] } }Observed result after fix: The rendered Feishu card now contains a native
actionrow with interactive buttons, and button values are emitted as structuredocf1envelopes instead of being flattened into markdown bullet text.What was not tested: Live Feishu delivery and callback handling against a real tenant/app.
Fixes #85959