mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-18 22:37:26 +00:00
fix: harden discord media fallback regressions (#28906) (thanks @Sid-Qin)
This commit is contained in:
@@ -111,6 +111,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Discord/Inbound media fallback: preserve attachment and sticker metadata when Discord CDN fetch/save fails by keeping URL-based media entries in context, with regression coverage for save failures and mixed success/failure ordering. Landed from contributor PR #28906 by @Sid-Qin. Thanks @Sid-Qin.
|
||||
- Docs/Docker images: clarify the official GHCR image source and tag guidance (`main`, `latest`, `<version>`), and document that `OPENCLAW_IMAGE` skips local image builds but still uses the repo-local compose/setup flow. (#27214, #31180) Fixes #15655. Thanks @ipl31.
|
||||
- Agents/Model fallback: classify additional network transport errors (`ECONNREFUSED`, `ENETUNREACH`, `EHOSTUNREACH`, `ENETRESET`, `EAI_AGAIN`) as failover-worthy so fallback chains advance when primary providers are unreachable. Landed from contributor PR #19077 by @ayanesakura. Thanks @ayanesakura.
|
||||
- Agents/Copilot token refresh: refresh GitHub Copilot runtime API tokens after auth-expiry failures and re-run with the renewed token so long-running embedded/subagent turns do not fail on mid-session 401 expiry. Landed from contributor PR #8805 by @Arthur742Ramos. Thanks @Arthur742Ramos.
|
||||
|
||||
@@ -334,6 +334,83 @@ describe("resolveMediaList", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("falls back to URL when saveMediaBuffer fails", async () => {
|
||||
const attachment = {
|
||||
id: "att-save-fail",
|
||||
url: "https://cdn.discordapp.com/attachments/1/photo.png",
|
||||
filename: "photo.png",
|
||||
content_type: "image/png",
|
||||
};
|
||||
fetchRemoteMedia.mockResolvedValueOnce({
|
||||
buffer: Buffer.from("image"),
|
||||
contentType: "image/png",
|
||||
});
|
||||
saveMediaBuffer.mockRejectedValueOnce(new Error("disk full"));
|
||||
|
||||
const result = await resolveMediaList(
|
||||
asMessage({
|
||||
attachments: [attachment],
|
||||
}),
|
||||
512,
|
||||
);
|
||||
|
||||
expect(fetchRemoteMedia).toHaveBeenCalledTimes(1);
|
||||
expect(saveMediaBuffer).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual([
|
||||
{
|
||||
path: attachment.url,
|
||||
contentType: "image/png",
|
||||
placeholder: "<media:image>",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("preserves downloaded attachments alongside failed ones", async () => {
|
||||
const goodAttachment = {
|
||||
id: "att-good",
|
||||
url: "https://cdn.discordapp.com/attachments/1/good.png",
|
||||
filename: "good.png",
|
||||
content_type: "image/png",
|
||||
};
|
||||
const badAttachment = {
|
||||
id: "att-bad",
|
||||
url: "https://cdn.discordapp.com/attachments/1/bad.pdf",
|
||||
filename: "bad.pdf",
|
||||
content_type: "application/pdf",
|
||||
};
|
||||
|
||||
fetchRemoteMedia
|
||||
.mockResolvedValueOnce({
|
||||
buffer: Buffer.from("image"),
|
||||
contentType: "image/png",
|
||||
})
|
||||
.mockRejectedValueOnce(new Error("network timeout"));
|
||||
saveMediaBuffer.mockResolvedValueOnce({
|
||||
path: "/tmp/good.png",
|
||||
contentType: "image/png",
|
||||
});
|
||||
|
||||
const result = await resolveMediaList(
|
||||
asMessage({
|
||||
attachments: [goodAttachment, badAttachment],
|
||||
}),
|
||||
512,
|
||||
);
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
path: "/tmp/good.png",
|
||||
contentType: "image/png",
|
||||
placeholder: "<media:image>",
|
||||
},
|
||||
{
|
||||
path: badAttachment.url,
|
||||
contentType: "application/pdf",
|
||||
placeholder: "<media:document>",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps sticker metadata when sticker download fails", async () => {
|
||||
const sticker = {
|
||||
id: "sticker-fallback",
|
||||
|
||||
Reference in New Issue
Block a user