fix: prevent infinite retry loop for images exceeding 5MB
- Change MAX_IMAGE_BYTES from 6MB to 5MB to match Anthropic API limit - Add isImageSizeError() to detect image size errors from API - Handle image size errors with user-friendly message instead of retry - Prevent failover for image size errors (not retriable) Fixes #2271
This commit is contained in:
parent
24902880de
commit
b59ea0e3f3
@ -23,6 +23,7 @@ export {
|
|||||||
isFailoverAssistantError,
|
isFailoverAssistantError,
|
||||||
isFailoverErrorMessage,
|
isFailoverErrorMessage,
|
||||||
isImageDimensionErrorMessage,
|
isImageDimensionErrorMessage,
|
||||||
|
isImageSizeError,
|
||||||
isOverloadedErrorMessage,
|
isOverloadedErrorMessage,
|
||||||
isRawApiErrorPayload,
|
isRawApiErrorPayload,
|
||||||
isRateLimitAssistantError,
|
isRateLimitAssistantError,
|
||||||
|
|||||||
@ -467,6 +467,12 @@ export function isImageDimensionErrorMessage(raw: string): boolean {
|
|||||||
return Boolean(parseImageDimensionError(raw));
|
return Boolean(parseImageDimensionError(raw));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isImageSizeError(errorMessage?: string): boolean {
|
||||||
|
if (!errorMessage) return false;
|
||||||
|
const lower = errorMessage.toLowerCase();
|
||||||
|
return lower.includes("image exceeds") && lower.includes("mb");
|
||||||
|
}
|
||||||
|
|
||||||
export function isCloudCodeAssistFormatError(raw: string): boolean {
|
export function isCloudCodeAssistFormatError(raw: string): boolean {
|
||||||
return !isImageDimensionErrorMessage(raw) && matchesErrorPatterns(raw, ERROR_PATTERNS.format);
|
return !isImageDimensionErrorMessage(raw) && matchesErrorPatterns(raw, ERROR_PATTERNS.format);
|
||||||
}
|
}
|
||||||
@ -478,6 +484,7 @@ export function isAuthAssistantError(msg: AssistantMessage | undefined): boolean
|
|||||||
|
|
||||||
export function classifyFailoverReason(raw: string): FailoverReason | null {
|
export function classifyFailoverReason(raw: string): FailoverReason | null {
|
||||||
if (isImageDimensionErrorMessage(raw)) return null;
|
if (isImageDimensionErrorMessage(raw)) return null;
|
||||||
|
if (isImageSizeError(raw)) return null;
|
||||||
if (isRateLimitErrorMessage(raw)) return "rate_limit";
|
if (isRateLimitErrorMessage(raw)) return "rate_limit";
|
||||||
if (isOverloadedErrorMessage(raw)) return "rate_limit";
|
if (isOverloadedErrorMessage(raw)) return "rate_limit";
|
||||||
if (isCloudCodeAssistFormatError(raw)) return "format";
|
if (isCloudCodeAssistFormatError(raw)) return "format";
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import {
|
|||||||
isContextOverflowError,
|
isContextOverflowError,
|
||||||
isFailoverAssistantError,
|
isFailoverAssistantError,
|
||||||
isFailoverErrorMessage,
|
isFailoverErrorMessage,
|
||||||
|
isImageSizeError,
|
||||||
parseImageDimensionError,
|
parseImageDimensionError,
|
||||||
isRateLimitAssistantError,
|
isRateLimitAssistantError,
|
||||||
isTimeoutErrorMessage,
|
isTimeoutErrorMessage,
|
||||||
@ -440,6 +441,29 @@ export async function runEmbeddedPiAgent(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// Handle image size errors with a user-friendly message (no retry needed)
|
||||||
|
if (isImageSizeError(errorText)) {
|
||||||
|
return {
|
||||||
|
payloads: [
|
||||||
|
{
|
||||||
|
text:
|
||||||
|
"Image too large for the model (max 5MB). " +
|
||||||
|
"Please compress or resize the image and try again.",
|
||||||
|
isError: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
meta: {
|
||||||
|
durationMs: Date.now() - started,
|
||||||
|
agentMeta: {
|
||||||
|
sessionId: sessionIdUsed,
|
||||||
|
provider,
|
||||||
|
model: model.id,
|
||||||
|
},
|
||||||
|
systemPromptReport: attempt.systemPromptReport,
|
||||||
|
error: { kind: "image_size", message: errorText },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
const promptFailoverReason = classifyFailoverReason(errorText);
|
const promptFailoverReason = classifyFailoverReason(errorText);
|
||||||
if (promptFailoverReason && promptFailoverReason !== "timeout" && lastProfileId) {
|
if (promptFailoverReason && promptFailoverReason !== "timeout" && lastProfileId) {
|
||||||
await markAuthProfileFailure({
|
await markAuthProfileFailure({
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export type EmbeddedPiRunMeta = {
|
|||||||
aborted?: boolean;
|
aborted?: boolean;
|
||||||
systemPromptReport?: SessionSystemPromptReport;
|
systemPromptReport?: SessionSystemPromptReport;
|
||||||
error?: {
|
error?: {
|
||||||
kind: "context_overflow" | "compaction_failure" | "role_ordering";
|
kind: "context_overflow" | "compaction_failure" | "role_ordering" | "image_size";
|
||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
/** Stop reason for the agent run (e.g., "completed", "tool_calls"). */
|
/** Stop reason for the agent run (e.g., "completed", "tool_calls"). */
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export const MAX_IMAGE_BYTES = 6 * 1024 * 1024; // 6MB
|
export const MAX_IMAGE_BYTES = 5 * 1024 * 1024; // 5MB (Anthropic API limit)
|
||||||
export const MAX_AUDIO_BYTES = 16 * 1024 * 1024; // 16MB
|
export const MAX_AUDIO_BYTES = 16 * 1024 * 1024; // 16MB
|
||||||
export const MAX_VIDEO_BYTES = 16 * 1024 * 1024; // 16MB
|
export const MAX_VIDEO_BYTES = 16 * 1024 * 1024; // 16MB
|
||||||
export const MAX_DOCUMENT_BYTES = 100 * 1024 * 1024; // 100MB
|
export const MAX_DOCUMENT_BYTES = 100 * 1024 * 1024; // 100MB
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user