fix: sanitize oversized image payloads

This commit is contained in:
Peter Steinberger
2026-01-18 15:19:25 +00:00
parent 891a2cc64a
commit 9c06689569
10 changed files with 208 additions and 17 deletions

View File

@@ -31,6 +31,7 @@ import {
isContextOverflowError,
isFailoverAssistantError,
isFailoverErrorMessage,
parseImageDimensionError,
isRateLimitAssistantError,
isTimeoutErrorMessage,
pickFallbackThinkingLevel,
@@ -357,6 +358,26 @@ export async function runEmbeddedPiAgent(
const failoverFailure = isFailoverAssistantError(lastAssistant);
const assistantFailoverReason = classifyFailoverReason(lastAssistant?.errorMessage ?? "");
const cloudCodeAssistFormatError = attempt.cloudCodeAssistFormatError;
const imageDimensionError = parseImageDimensionError(lastAssistant?.errorMessage ?? "");
if (imageDimensionError && lastProfileId) {
const details = [
imageDimensionError.messageIndex !== undefined
? `message=${imageDimensionError.messageIndex}`
: null,
imageDimensionError.contentIndex !== undefined
? `content=${imageDimensionError.contentIndex}`
: null,
imageDimensionError.maxDimensionPx !== undefined
? `limit=${imageDimensionError.maxDimensionPx}px`
: null,
]
.filter(Boolean)
.join(" ");
log.warn(
`Profile ${lastProfileId} rejected image payload${details ? ` (${details})` : ""}.`,
);
}
// Treat timeout as potential rate limit (Antigravity hangs on rate limit)
const shouldRotate = (!aborted && failoverFailure) || timedOut;

View File

@@ -5,6 +5,7 @@ import { fileURLToPath } from "node:url";
import type { ImageContent } from "@mariozechner/pi-ai";
import { assertSandboxPath } from "../../sandbox-paths.js";
import { sanitizeImageBlocks } from "../../tool-images.js";
import { extractTextFromMessage } from "../../../tui/tui-formatters.js";
import { loadWebMedia } from "../../../web/media.js";
import { resolveUserPath } from "../../../utils.js";
@@ -48,6 +49,17 @@ function isImageExtension(filePath: string): boolean {
return IMAGE_EXTENSIONS.has(ext);
}
async function sanitizeImagesWithLog(
images: ImageContent[],
label: string,
): Promise<ImageContent[]> {
const { images: sanitized, dropped } = await sanitizeImageBlocks(images, label);
if (dropped > 0) {
log.warn(`Native image: dropped ${dropped} image(s) after sanitization (${label}).`);
}
return sanitized;
}
/**
* Detects image references in a user prompt.
*
@@ -392,9 +404,18 @@ export async function detectAndLoadPromptImages(params: {
}
}
const sanitizedPromptImages = await sanitizeImagesWithLog(promptImages, "prompt:images");
const sanitizedHistoryImagesByIndex = new Map<number, ImageContent[]>();
for (const [index, images] of historyImagesByIndex) {
const sanitized = await sanitizeImagesWithLog(images, `history:images:${index}`);
if (sanitized.length > 0) {
sanitizedHistoryImagesByIndex.set(index, sanitized);
}
}
return {
images: promptImages,
historyImagesByIndex,
images: sanitizedPromptImages,
historyImagesByIndex: sanitizedHistoryImagesByIndex,
detectedRefs: allRefs,
loadedCount,
skippedCount,