mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 08:07:40 +00:00
fix(slack): download all files in multi-image messages (#15447)
* fix(slack): download all files in multi-image messages resolveSlackMedia() previously returned after downloading the first file, causing multi-image Slack messages to lose all but the first attachment. This changes the function to collect all successfully downloaded files into an array, matching the pattern already used by Telegram, Line, Discord, and iMessage adapters. The prepare handler now populates MediaPaths, MediaUrls, and MediaTypes arrays so downstream media processing (vision, sandbox staging, media notes) works correctly with multiple attachments. Fixes #11892, #7536 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(slack): preserve MediaTypes index alignment with MediaPaths/MediaUrls The filter(Boolean) on MediaTypes removed entries with undefined contentType, shrinking the array and breaking index correlation with MediaPaths and MediaUrls. Downstream code (media-note.ts, attachments.ts) requires these arrays to have equal lengths for correct per-attachment MIME type lookup. Replace filter(Boolean) with a nullish coalescing fallback to "application/octet-stream". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(slack): align MediaType fallback and tests (#15447) (thanks @CommanderCrowCode) * fix: unblock plugin-sdk account-id typing (#15447) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -267,6 +267,7 @@ describe("resolveSlackMedia", () => {
|
||||
});
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result).toHaveLength(1);
|
||||
// saveMediaBuffer should receive the overridden audio/mp4
|
||||
expect(saveMediaBufferMock).toHaveBeenCalledWith(
|
||||
expect.any(Buffer),
|
||||
@@ -276,7 +277,7 @@ describe("resolveSlackMedia", () => {
|
||||
);
|
||||
// Returned contentType must be the overridden value, not the
|
||||
// re-detected video/mp4 from saveMediaBuffer
|
||||
expect(result!.contentType).toBe("audio/mp4");
|
||||
expect(result![0]?.contentType).toBe("audio/mp4");
|
||||
});
|
||||
|
||||
it("preserves original MIME for non-voice Slack files", async () => {
|
||||
@@ -304,12 +305,14 @@ describe("resolveSlackMedia", () => {
|
||||
});
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result).toHaveLength(1);
|
||||
expect(saveMediaBufferMock).toHaveBeenCalledWith(
|
||||
expect.any(Buffer),
|
||||
"video/mp4",
|
||||
"inbound",
|
||||
16 * 1024 * 1024,
|
||||
);
|
||||
expect(result![0]?.contentType).toBe("video/mp4");
|
||||
});
|
||||
|
||||
it("falls through to next file when first file returns error", async () => {
|
||||
@@ -338,8 +341,41 @@ describe("resolveSlackMedia", () => {
|
||||
});
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result).toHaveLength(1);
|
||||
expect(mockFetch).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("returns all successfully downloaded files as an array", async () => {
|
||||
vi.spyOn(mediaStore, "saveMediaBuffer")
|
||||
.mockResolvedValueOnce({ path: "/tmp/a.jpg", contentType: "image/jpeg" })
|
||||
.mockResolvedValueOnce({ path: "/tmp/b.png", contentType: "image/png" });
|
||||
|
||||
const responseA = new Response(Buffer.from("image a"), {
|
||||
status: 200,
|
||||
headers: { "content-type": "image/jpeg" },
|
||||
});
|
||||
const responseB = new Response(Buffer.from("image b"), {
|
||||
status: 200,
|
||||
headers: { "content-type": "image/png" },
|
||||
});
|
||||
|
||||
mockFetch.mockResolvedValueOnce(responseA).mockResolvedValueOnce(responseB);
|
||||
|
||||
const result = await resolveSlackMedia({
|
||||
files: [
|
||||
{ url_private: "https://files.slack.com/a.jpg", name: "a.jpg" },
|
||||
{ url_private: "https://files.slack.com/b.png", name: "b.png" },
|
||||
],
|
||||
token: "xoxb-test-token",
|
||||
maxBytes: 1024 * 1024,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result![0].path).toBe("/tmp/a.jpg");
|
||||
expect(result![0].placeholder).toBe("[Slack file: a.jpg]");
|
||||
expect(result![1].path).toBe("/tmp/b.png");
|
||||
expect(result![1].placeholder).toBe("[Slack file: b.png]");
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveSlackThreadHistory", () => {
|
||||
|
||||
Reference in New Issue
Block a user