fix(agents): include filenames in image resize logs

This commit is contained in:
Peter Steinberger
2026-02-21 13:16:23 +00:00
parent 3cfb402bda
commit 2706cbd6d7
3 changed files with 160 additions and 2 deletions

View File

@@ -70,12 +70,87 @@ function formatBytesShort(bytes: number): string {
return `${(bytes / (1024 * 1024)).toFixed(2)}MB`;
}
function parseMediaPathFromText(text: string): string | undefined {
for (const line of text.split(/\r?\n/u)) {
const trimmed = line.trim();
if (!trimmed.startsWith("MEDIA:")) {
continue;
}
const raw = trimmed.slice("MEDIA:".length).trim();
if (!raw) {
continue;
}
const backtickWrapped = raw.match(/^`([^`]+)`$/u);
return (backtickWrapped?.[1] ?? raw).trim();
}
return undefined;
}
function fileNameFromPathLike(pathLike: string): string | undefined {
const value = pathLike.trim();
if (!value) {
return undefined;
}
try {
const url = new URL(value);
const candidate = url.pathname.split("/").filter(Boolean).at(-1);
return candidate && candidate.length > 0 ? candidate : undefined;
} catch {
// Not a URL; continue with path-like parsing.
}
const normalized = value.replaceAll("\\", "/");
const candidate = normalized.split("/").filter(Boolean).at(-1);
return candidate && candidate.length > 0 ? candidate : undefined;
}
function inferImageFileName(params: {
block: ImageContentBlock;
label?: string;
mediaPathHint?: string;
}): string | undefined {
const rec = params.block as unknown as Record<string, unknown>;
const explicitKeys = ["fileName", "filename", "path", "url"] as const;
for (const key of explicitKeys) {
const raw = rec[key];
if (typeof raw !== "string" || raw.trim().length === 0) {
continue;
}
const candidate = fileNameFromPathLike(raw);
if (candidate) {
return candidate;
}
}
if (typeof rec.name === "string" && rec.name.trim().length > 0) {
return rec.name.trim();
}
if (params.mediaPathHint) {
const candidate = fileNameFromPathLike(params.mediaPathHint);
if (candidate) {
return candidate;
}
}
if (typeof params.label === "string" && params.label.startsWith("read:")) {
const candidate = fileNameFromPathLike(params.label.slice("read:".length));
if (candidate) {
return candidate;
}
}
return undefined;
}
async function resizeImageBase64IfNeeded(params: {
base64: string;
mimeType: string;
maxDimensionPx: number;
maxBytes: number;
label?: string;
fileName?: string;
}): Promise<{
base64: string;
mimeType: string;
@@ -127,14 +202,18 @@ async function resizeImageBase64IfNeeded(params: {
typeof width === "number" && typeof height === "number"
? `${width}x${height}px`
: "unknown";
const sourceWithFile = params.fileName
? `${params.fileName} ${sourcePixels}`
: sourcePixels;
const byteReductionPct =
buf.byteLength > 0
? Number((((buf.byteLength - out.byteLength) / buf.byteLength) * 100).toFixed(1))
: 0;
log.info(
`Image resized to fit limits: ${sourcePixels} ${formatBytesShort(buf.byteLength)} -> ${formatBytesShort(out.byteLength)} (-${byteReductionPct}%)`,
`Image resized to fit limits: ${sourceWithFile} ${formatBytesShort(buf.byteLength)} -> ${formatBytesShort(out.byteLength)} (-${byteReductionPct}%)`,
{
label: params.label,
fileName: params.fileName,
sourceMimeType: params.mimeType,
sourceWidth: width,
sourceHeight: height,
@@ -166,10 +245,12 @@ async function resizeImageBase64IfNeeded(params: {
const gotMb = (best.byteLength / (1024 * 1024)).toFixed(2);
const sourcePixels =
typeof width === "number" && typeof height === "number" ? `${width}x${height}px` : "unknown";
const sourceWithFile = params.fileName ? `${params.fileName} ${sourcePixels}` : sourcePixels;
log.warn(
`Image resize failed to fit limits: ${sourcePixels} best=${formatBytesShort(best.byteLength)} limit=${formatBytesShort(params.maxBytes)}`,
`Image resize failed to fit limits: ${sourceWithFile} best=${formatBytesShort(best.byteLength)} limit=${formatBytesShort(params.maxBytes)}`,
{
label: params.label,
fileName: params.fileName,
sourceMimeType: params.mimeType,
sourceWidth: width,
sourceHeight: height,
@@ -192,8 +273,16 @@ export async function sanitizeContentBlocksImages(
const maxDimensionPx = Math.max(opts.maxDimensionPx ?? MAX_IMAGE_DIMENSION_PX, 1);
const maxBytes = Math.max(opts.maxBytes ?? MAX_IMAGE_BYTES, 1);
const out: ToolContentBlock[] = [];
let mediaPathHint: string | undefined;
for (const block of blocks) {
if (isTextBlock(block)) {
const mediaPath = parseMediaPathFromText(block.text);
if (mediaPath) {
mediaPathHint = mediaPath;
}
}
if (!isImageBlock(block)) {
out.push(block);
continue;
@@ -211,12 +300,14 @@ export async function sanitizeContentBlocksImages(
try {
const inferredMimeType = inferMimeTypeFromBase64(data);
const mimeType = inferredMimeType ?? block.mimeType;
const fileName = inferImageFileName({ block, label, mediaPathHint });
const resized = await resizeImageBase64IfNeeded({
base64: data,
mimeType,
maxDimensionPx,
maxBytes,
label,
fileName,
});
out.push({
...block,