diff --git a/extensions/feishu/src/media.test.ts b/extensions/feishu/src/media.test.ts index 055ddd531c3..906a4170772 100644 --- a/extensions/feishu/src/media.test.ts +++ b/extensions/feishu/src/media.test.ts @@ -295,15 +295,20 @@ describe("sendMediaFeishu msg_type routing", () => { kind: "image", contentType: "image/png", }); + resolveFeishuAccountMock.mockReturnValueOnce({ + configured: true, + accountId: "main", + config: { localRoots: "any" }, + }); await sendMediaFeishu({ cfg: { channels: { feishu: { localRoots: "any" } } } as any, to: "user:ou_target", - mediaUrl: "/Users/zhengxing/openclaw/workspace/ask_official.png", + mediaUrl: "/local/feishu/workspace/ask_official.png", }); expect(loadWebMediaMock).toHaveBeenCalledWith( - "/Users/zhengxing/openclaw/workspace/ask_official.png", + "/local/feishu/workspace/ask_official.png", expect.objectContaining({ localRoots: "any", readFile: expect.any(Function), @@ -320,6 +325,11 @@ describe("sendMediaFeishu msg_type routing", () => { }); const channelRoots = ["/custom/feishu/root"]; + resolveFeishuAccountMock.mockReturnValueOnce({ + configured: true, + accountId: "main", + config: { localRoots: channelRoots }, + }); await sendMediaFeishu({ cfg: { channels: { feishu: { localRoots: channelRoots } } } as any, to: "user:ou_target", diff --git a/extensions/feishu/src/media.ts b/extensions/feishu/src/media.ts index c5046792f86..db95a07a51e 100644 --- a/extensions/feishu/src/media.ts +++ b/extensions/feishu/src/media.ts @@ -415,15 +415,14 @@ export function detectFileType( } /** - * Resolve effective localRoots for loadWebMedia: channel config (localRoots) overrides - * context mediaLocalRoots. Supports channels.feishu.localRoots = "any" or string[]. + * Resolve effective localRoots for loadWebMedia from merged account config (so + * channels.feishu.accounts..localRoots overrides top-level). Supports "any" or string[]. */ function resolveFeishuMediaLocalRoots(params: { - cfg: ClawdbotConfig; + feishuConfig: FeishuConfig | undefined; mediaLocalRoots?: readonly string[]; }): readonly string[] | "any" | undefined { - const feishuCfg = params.cfg.channels?.feishu as FeishuConfig | undefined; - const channelRoots = feishuCfg?.localRoots; + const channelRoots = params.feishuConfig?.localRoots; if (channelRoots === "any") { return "any"; } @@ -435,8 +434,8 @@ function resolveFeishuMediaLocalRoots(params: { /** * Upload and send media (image or file) from URL, local path, or buffer. - * When mediaUrl is a local path, allowed roots come from channels.feishu.localRoots - * (or "any") or from core outbound mediaLocalRoots. + * When mediaUrl is a local path, allowed roots come from merged Feishu config + * (channels.feishu.localRoots or channels.feishu.accounts..localRoots) or core mediaLocalRoots. */ export async function sendMediaFeishu(params: { cfg: ClawdbotConfig; @@ -474,7 +473,10 @@ export async function sendMediaFeishu(params: { buffer = mediaBuffer; name = fileName ?? "file"; } else if (mediaUrl) { - const localRoots = resolveFeishuMediaLocalRoots({ cfg, mediaLocalRoots }); + const localRoots = resolveFeishuMediaLocalRoots({ + feishuConfig: account.config, + mediaLocalRoots, + }); const loadOptions: { maxBytes: number; optimizeImages: boolean;