Skip to content

Commit e4cb6a8

Browse files
4ierTakhoffman
andauthored
fix(feishu): handle message_type "media" for video downloads (#25502) thanks @4ier
Verified: - pnpm build - pnpm check - pnpm test:macmini Co-authored-by: 4ier <[email protected]> Co-authored-by: Tak Hoffman <[email protected]>
1 parent d9230b1 commit e4cb6a8

File tree

3 files changed

+53
-2
lines changed

3 files changed

+53
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai
2626
- Feishu/Typing backoff: re-throw Feishu typing add/remove rate-limit and quota errors (`429`, `99991400`, `99991403`) and detect SDK non-throwing backoff responses so the typing keepalive circuit breaker can stop retries instead of looping indefinitely. (#28494)
2727
- Feishu/Probe status caching: cache successful `probeFeishu()` bot-info results for 10 minutes (bounded cache with per-account keying) to reduce repeated status/onboarding probe API calls, while bypassing cache for failures and exceptions. (#28907) Thanks @Glucksberg.
2828
- Feishu/Opus media send type: send `.opus` attachments with `msg_type: "audio"` (instead of `"media"`) so Feishu voice messages deliver correctly while `.mp4` remains `msg_type: "media"` and documents remain `msg_type: "file"`. (#28269) Thanks @Glucksberg.
29+
- Feishu/Mobile video media type: treat inbound `message_type: "media"` as video-equivalent for media key extraction, placeholder inference, and media download resolution so mobile-app video sends ingest correctly. (#25502) Thanks @4ier.
2930
- Feishu/Inbound rich-text parsing: preserve `share_chat` payload summaries when available and add explicit parsing for rich-text `code`/`code_block`/`pre` tags so forwarded and code-heavy messages keep useful context in agent input. (#28591) Thanks @kevinWangSheng.
3031
- Feishu/Local media sends: propagate `mediaLocalRoots` through Feishu outbound media sending into `loadWebMedia` so local path attachments work with post-CVE local-root enforcement. (#27884) Thanks @joelnishanth.
3132
- Feishu/Group sender allowlist fallback: add global `channels.feishu.groupSenderAllowFrom` sender authorization for group chats, with per-group `groups.<id>.allowFrom` precedence and regression coverage for allow/block/precedence behavior. (#29174) Thanks @1MoreBuild.

extensions/feishu/src/bot.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,54 @@ describe("handleFeishuMessage command authorization", () => {
571571
);
572572
});
573573

574+
it("uses media message_type file_key (not thumbnail image_key) for inbound mobile video download", async () => {
575+
mockShouldComputeCommandAuthorized.mockReturnValue(false);
576+
577+
const cfg: ClawdbotConfig = {
578+
channels: {
579+
feishu: {
580+
dmPolicy: "open",
581+
},
582+
},
583+
} as ClawdbotConfig;
584+
585+
const event: FeishuMessageEvent = {
586+
sender: {
587+
sender_id: {
588+
open_id: "ou-sender",
589+
},
590+
},
591+
message: {
592+
message_id: "msg-media-inbound",
593+
chat_id: "oc-dm",
594+
chat_type: "p2p",
595+
message_type: "media",
596+
content: JSON.stringify({
597+
file_key: "file_media_payload",
598+
image_key: "img_media_thumb",
599+
file_name: "mobile.mp4",
600+
}),
601+
},
602+
};
603+
604+
await dispatchMessage({ cfg, event });
605+
606+
expect(mockDownloadMessageResourceFeishu).toHaveBeenCalledWith(
607+
expect.objectContaining({
608+
messageId: "msg-media-inbound",
609+
fileKey: "file_media_payload",
610+
type: "file",
611+
}),
612+
);
613+
expect(mockSaveMediaBuffer).toHaveBeenCalledWith(
614+
expect.any(Buffer),
615+
"video/mp4",
616+
"inbound",
617+
expect.any(Number),
618+
"clip.mp4",
619+
);
620+
});
621+
574622
it("includes message_id in BodyForAgent on its own line", async () => {
575623
mockShouldComputeCommandAuthorized.mockReturnValue(false);
576624

extensions/feishu/src/bot.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,8 @@ function parseMediaKeys(
371371
case "audio":
372372
return { fileKey };
373373
case "video":
374-
// Video has both file_key (video) and image_key (thumbnail)
374+
case "media":
375+
// Video/media has both file_key (video) and image_key (thumbnail)
375376
return { fileKey, imageKey };
376377
case "sticker":
377378
return { fileKey };
@@ -471,6 +472,7 @@ function inferPlaceholder(messageType: string): string {
471472
case "audio":
472473
return "<media:audio>";
473474
case "video":
475+
case "media":
474476
return "<media:video>";
475477
case "sticker":
476478
return "<media:sticker>";
@@ -495,7 +497,7 @@ async function resolveFeishuMediaList(params: {
495497
const { cfg, messageId, messageType, content, maxBytes, log, accountId } = params;
496498

497499
// Only process media message types (including post for embedded images)
498-
const mediaTypes = ["image", "file", "audio", "video", "sticker", "post"];
500+
const mediaTypes = ["image", "file", "audio", "video", "media", "sticker", "post"];
499501
if (!mediaTypes.includes(messageType)) {
500502
return [];
501503
}

0 commit comments

Comments
 (0)