Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(feishu): preserve command guidance marker through core presentati…
…on rendering
  • Loading branch information
xialonglee authored and steipete committed Jul 2, 2026
commit 34545aef1f65425e8e082cc325c37648249aed03
31 changes: 31 additions & 0 deletions extensions/feishu/src/outbound.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,37 @@ describe("feishuOutbound.sendPayload native cards", () => {
expect(commentThreadParams()?.content).toBe("Review this\n\n- Disabled Approve");
expectFeishuResult(result, "reply_msg");
});

it("adds command guidance when presentation is stripped but channelData carries the rendered-command marker", async () => {
// Simulates the core delivery path: renderPresentationForDelivery strips
// the presentation field, but renderFeishuPresentationPayload sets
// hasRenderedCommandAction in channelData.feishu so the comment-target
// branch in sendPayload can still detect that a command was rendered.
// The payload includes a minimal card in channelData.feishu.card so
// buildFeishuPayloadCard does not return undefined and skip the
// comment-target handler entirely.
const result = await feishuOutbound.sendPayload?.({
cfg: emptyConfig,
to: "comment:docx:doxcn123:7623358762119646411",
text: "Review this",
accountId: "main",
payload: {
text: "Review this\n\n- Approve: `/approve req_1`",
channelData: {
feishu: {
card: { body: { elements: [{ tag: "hr" }] } },
hasRenderedCommandAction: true,
},
},
},
});

expect(sendCardFeishuMock).not.toHaveBeenCalled();
expect(commentThreadParams()?.content).toBe(
"Review this\n\n- Approve: `/approve req_1`\n\n> Interactive buttons are unavailable in Feishu document comments. You can type the command shown above manually.",
);
expectFeishuResult(result, "reply_msg");
});
});

describe("feishuOutbound comment-thread routing", () => {
Expand Down
13 changes: 12 additions & 1 deletion extensions/feishu/src/outbound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,11 @@ function renderFeishuPresentationPayload({
const existingFeishuData = isRecord(payload.channelData?.feishu)
? payload.channelData.feishu
: undefined;
// Preserve a rendered-command marker in channelData so the downstream
// comment-target branch in sendPayload can detect that a command was
// rendered even after core renderPresentationForDelivery strips the
// presentation field before calling sendPayload.
const hasCmd = hasRenderedCommandAction(presentation?.blocks);
return {
...payload,
text: renderMessagePresentationFallbackText({ text: payload.text, presentation }),
Expand All @@ -345,6 +350,7 @@ function renderFeishuPresentationPayload({
feishu: {
...existingFeishuData,
card,
...(hasCmd ? { hasRenderedCommandAction: true } : {}),
},
},
};
Expand Down Expand Up @@ -516,7 +522,12 @@ export const feishuOutbound: ChannelOutboundAdapter = {
text: ctx.payload.text,
presentation: normalizedPresentation,
});
const hasCmd = hasRenderedCommandAction(normalizedPresentation?.blocks);
const hasCmd =
hasRenderedCommandAction(normalizedPresentation?.blocks) ||
// When core delivery strips presentation via renderPresentationForDelivery
// before calling sendPayload, the blocks check above returns false. Fall
// back to the marker set by renderFeishuPresentationPayload.
Boolean(ctx.payload.channelData?.feishu?.hasRenderedCommandAction);
const text = hasCmd
? `${presentationFallbackText}\n\n> Interactive buttons are unavailable in Feishu document comments. You can type the command shown above manually.`
: presentationFallbackText;
Expand Down