Skip to content

Commit 3dcff3b

Browse files
committed
fix(media): require HEIC conversion fallback
1 parent d8da04e commit 3dcff3b

3 files changed

Lines changed: 20 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Docs: https://docs.openclaw.ai
5656

5757
### Fixes
5858

59+
- Media/images: keep HEIC/HEIF attachments fail-closed when optional Sharp conversion is unavailable instead of sending originals that still need conversion. Thanks @vincentkoc.
5960
- Telegram/streaming: sanitize tool-progress draft preview backticks before shared compaction, so long backtick-heavy progress text still renders inside the safe code-formatted preview instead of collapsing to an ellipsis.
6061
- UI/chat: remove the unsupported `line-clamp` declaration from the chat queue text rule to eliminate Firefox console noise without changing visible truncation behavior. Thanks @ZanderH-code.
6162
- Agents/Pi: suppress persistence for synthetic mid-turn overflow continuation prompts, so transcript-retry recovery does not write the "continue from transcript" prompt as a new user turn. Thanks @vincentkoc.

src/media/web-media.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ describe("loadWebMedia", () => {
176176
throw new Error("should not optimize png");
177177
}),
178178
resizeToJpeg: vi.fn(async () => {
179-
throw new Error("should not resize jpeg");
179+
throw new Error(
180+
"Optional dependency sharp is required for image attachment processing | Cannot find package 'sharp' imported from image-ops.js",
181+
);
180182
}),
181183
}));
182184
try {
@@ -210,6 +212,17 @@ describe("loadWebMedia", () => {
210212
});
211213
});
212214

215+
it("does not send original HEIC media when optional sharp conversion is unavailable", async () => {
216+
await withUnavailableImageOptimizer(async () => {
217+
const heicFile = path.join(fixtureRoot, "photo.heic");
218+
await fs.writeFile(heicFile, Buffer.from("heic-source"));
219+
const { loadWebMedia: loadWebMediaWithMissingOptimizer } = await import("./web-media.js");
220+
await expect(
221+
loadWebMediaWithMissingOptimizer(heicFile, createLocalWebMediaOptions()),
222+
).rejects.toThrow(/Optional dependency sharp is required/);
223+
});
224+
});
225+
213226
it("resolves relative local media paths against the provided workspace directory", async () => {
214227
const result = await loadWebMedia("chart.png", {
215228
maxBytes: 1024 * 1024,

src/media/web-media.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,11 @@ async function loadWebMediaInternal(
413413
try {
414414
optimized = await optimizeImageWithFallback({ buffer, cap, meta });
415415
} catch (err) {
416-
if (isOptionalImageOptimizerUnavailable(err) && buffer.length <= cap) {
416+
if (
417+
isOptionalImageOptimizerUnavailable(err) &&
418+
!isHeicSource(meta ?? {}) &&
419+
buffer.length <= cap
420+
) {
417421
if (shouldLogVerbose()) {
418422
logVerbose(
419423
`Image optimizer unavailable; sending original ${formatMb(buffer.length)}MB media without optimization`,

0 commit comments

Comments
 (0)