fix: contain final reply media normalization failures

This commit is contained in:
Ayaan Zaidi
2026-03-07 10:43:31 +05:30
committed by Ayaan Zaidi
parent 059aedeb08
commit c943747d6b
2 changed files with 58 additions and 1 deletions

View File

@@ -58,6 +58,35 @@ describe("buildReplyPayloads media filter integration", () => {
});
});
it("drops only invalid media when reply media normalization fails", async () => {
const normalizeMediaPaths = async (payload: { mediaUrl?: string }) => {
if (payload.mediaUrl === "./bad.png") {
throw new Error("Path escapes sandbox root");
}
return payload;
};
const { replyPayloads } = await buildReplyPayloads({
...baseParams,
payloads: [
{ text: "keep text", mediaUrl: "./bad.png", audioAsVoice: true },
{ text: "keep second" },
],
normalizeMediaPaths,
});
expect(replyPayloads).toHaveLength(2);
expect(replyPayloads[0]).toMatchObject({
text: "keep text",
mediaUrl: undefined,
mediaUrls: undefined,
audioAsVoice: false,
});
expect(replyPayloads[1]).toMatchObject({
text: "keep second",
});
});
it("applies media filter after text filter", async () => {
const { replyPayloads } = await buildReplyPayloads({
...baseParams,

View File

@@ -20,6 +20,31 @@ import {
shouldSuppressMessagingToolReplies,
} from "./reply-payloads.js";
function hasPayloadMedia(payload: ReplyPayload): boolean {
return Boolean(payload.mediaUrl) || (payload.mediaUrls?.length ?? 0) > 0;
}
async function normalizeReplyPayloadMedia(params: {
payload: ReplyPayload;
normalizeMediaPaths?: (payload: ReplyPayload) => Promise<ReplyPayload>;
}): Promise<ReplyPayload> {
if (!params.normalizeMediaPaths || !hasPayloadMedia(params.payload)) {
return params.payload;
}
try {
return await params.normalizeMediaPaths(params.payload);
} catch (err) {
logVerbose(`reply payload media normalization failed: ${String(err)}`);
return {
...params.payload,
mediaUrl: undefined,
mediaUrls: undefined,
audioAsVoice: false,
};
}
}
async function normalizeSentMediaUrlsForDedupe(params: {
sentMediaUrls: string[];
normalizeMediaPaths?: (payload: ReplyPayload) => Promise<ReplyPayload>;
@@ -126,7 +151,10 @@ export async function buildReplyPayloads(params: {
silentToken: SILENT_REPLY_TOKEN,
parseMode: "always",
}).payload;
return params.normalizeMediaPaths ? await params.normalizeMediaPaths(parsed) : parsed;
return await normalizeReplyPayloadMedia({
payload: parsed,
normalizeMediaPaths: params.normalizeMediaPaths,
});
}),
)
).filter(isRenderablePayload);