fix: sanitize oversized image payloads
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user