mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-22 09:12:44 +00:00
fix(markdown): retry transient image decode failures
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
type ImageDecoder = (
|
||||
uri: string,
|
||||
success: (width: number, height: number) => void,
|
||||
failure: (error: unknown) => void,
|
||||
) => void;
|
||||
|
||||
export function decodeMarkdownImage(uri: string, decode: ImageDecoder): Promise<true> {
|
||||
return new Promise((resolve, reject) => {
|
||||
decode(
|
||||
uri,
|
||||
(width, height) => {
|
||||
if (width > 0 && height > 0) resolve(true);
|
||||
else reject(new Error("Image has no decodable dimensions"));
|
||||
},
|
||||
reject,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
|
||||
import type { AttachmentMetadata } from "@/attachments/types";
|
||||
import { resolveMarkdownPreviewImageSource } from "./image-source";
|
||||
import { prepareMarkdownSource } from "./source";
|
||||
import { decodeMarkdownImage } from "./image-decoding";
|
||||
|
||||
const urls = createAssistantImageAcquisitionCache<{ uri: string; attachment: AttachmentMetadata }>({
|
||||
capacity: 500,
|
||||
@@ -99,11 +100,15 @@ export function useMarkdownSource(text: string, context: MarkdownImageContext) {
|
||||
const decoded = useFetchQueries(
|
||||
displayUrls.map((uri, index) => ({
|
||||
queryKey: ["markdownImageDecode", occurrenceKey, uri ?? sources[index]],
|
||||
refetchOnReconnect: true,
|
||||
enabled: uri !== undefined,
|
||||
immutableWhen: () => true,
|
||||
dataShape: "value",
|
||||
gcTime: 0,
|
||||
queryFn: () => (uri ? canDecodeImage(uri) : Promise.resolve(false)),
|
||||
queryFn: () => {
|
||||
if (!uri) throw new Error("No image URL to decode");
|
||||
return decodeMarkdownImage(uri, Image.getSize);
|
||||
},
|
||||
})),
|
||||
);
|
||||
const unavailableImages = new Set(
|
||||
@@ -118,13 +123,3 @@ export function useMarkdownSource(text: string, context: MarkdownImageContext) {
|
||||
imageSources: Object.fromEntries([...resolved].map(([source, url]) => [url, source])),
|
||||
};
|
||||
}
|
||||
|
||||
function canDecodeImage(uri: string): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
Image.getSize(
|
||||
uri,
|
||||
(width, height) => resolve(width > 0 && height > 0),
|
||||
() => resolve(false),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import { decodeMarkdownImage } from "./image-decoding";
|
||||
import { createElement } from "react";
|
||||
import { MarkdownRendererFrame } from "./frame";
|
||||
import { describe, expect, it } from "vitest";
|
||||
@@ -348,3 +350,22 @@ it("preserves literal Markdown punctuation in unsupported and failed image label
|
||||
),
|
||||
).toBe(label);
|
||||
});
|
||||
|
||||
it("retries transient image decoding failures instead of caching an unavailable image", async () => {
|
||||
const client = new QueryClient();
|
||||
let attempts = 0;
|
||||
const decoded = await client.fetchQuery({
|
||||
queryKey: ["markdownImageDecode", "transient.png"],
|
||||
retry: 1,
|
||||
retryDelay: 0,
|
||||
queryFn: () =>
|
||||
decodeMarkdownImage("transient.png", (_uri, success, failure) => {
|
||||
attempts += 1;
|
||||
if (attempts === 1) failure(new Error("temporarily unavailable"));
|
||||
else success(20, 20);
|
||||
}),
|
||||
});
|
||||
expect(decoded).toBe(true);
|
||||
expect(attempts).toBe(2);
|
||||
client.clear();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user