feat(feishu): extract embedded video/media from post (rich text) messages (#21786)

* feat(feishu): extract embedded video/media from post (rich text) messages

Previously, parsePostContent() only extracted embedded images (img tags)
from rich text posts, ignoring embedded video/audio (media tags). Users
sending post messages with embedded videos would not have the media
downloaded or forwarded to the agent.

Changes:
- Extend parsePostContent() to also collect media tags with file_key
- Return new mediaKeys array alongside existing imageKeys
- Update resolveFeishuMediaList() to download embedded media files
  from post messages using the messageResource API
- Add appropriate logging for embedded media discovery and download

* Feishu: keep embedded post media payloads type-safe

* Feishu: format post parser after media tag extraction

---------

Co-authored-by: laopuhuluwa <laopuhuluwa@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
laopuhuluwa
2026-02-28 13:39:24 +08:00
committed by GitHub
parent b0a8909a73
commit 53a2e72fcb
4 changed files with 123 additions and 8 deletions

View File

@@ -682,6 +682,60 @@ describe("handleFeishuMessage command authorization", () => {
);
});
it("downloads embedded media tags from post messages as files", async () => {
mockShouldComputeCommandAuthorized.mockReturnValue(false);
const cfg: ClawdbotConfig = {
channels: {
feishu: {
dmPolicy: "open",
},
},
} as ClawdbotConfig;
const event: FeishuMessageEvent = {
sender: {
sender_id: {
open_id: "ou-sender",
},
},
message: {
message_id: "msg-post-media",
chat_id: "oc-dm",
chat_type: "p2p",
message_type: "post",
content: JSON.stringify({
title: "Rich text",
content: [
[
{
tag: "media",
file_key: "file_post_media_payload",
file_name: "embedded.mov",
},
],
],
}),
},
};
await dispatchMessage({ cfg, event });
expect(mockDownloadMessageResourceFeishu).toHaveBeenCalledWith(
expect.objectContaining({
messageId: "msg-post-media",
fileKey: "file_post_media_payload",
type: "file",
}),
);
expect(mockSaveMediaBuffer).toHaveBeenCalledWith(
expect.any(Buffer),
"video/mp4",
"inbound",
expect.any(Number),
);
});
it("includes message_id in BodyForAgent on its own line", async () => {
mockShouldComputeCommandAuthorized.mockReturnValue(false);