diff --git a/app/api/canvas/local-edit/route.ts b/app/api/canvas/local-edit/route.ts index 9db793cde..6aeb5aba3 100644 --- a/app/api/canvas/local-edit/route.ts +++ b/app/api/canvas/local-edit/route.ts @@ -1442,6 +1442,10 @@ export async function POST(request: NextRequest) { ? true : undefined, protectedRegions: scaleAdjustCompositeRegions, + rejectFailedCandidates: + useScaleAdjustCoordinateGuide && Boolean(scaleAdjustModelFamily) + ? true + : undefined, sourceImageUrl, regions: regions.map((region) => region.rect), ...(typeof scalePercent === "number" diff --git a/lib/canvas/generate-image.ts b/lib/canvas/generate-image.ts index 7dfbe27f7..03541d2dd 100644 --- a/lib/canvas/generate-image.ts +++ b/lib/canvas/generate-image.ts @@ -126,11 +126,13 @@ export interface CanvasGenerateImageResult { class ScaleAdjustOutputRejectedError extends Error { reason: string; diffScores?: number[]; + images?: ParsedImage[]; outsideDiffScores?: number[]; constructor(params: { reason: string; diffScores?: number[]; + images?: ParsedImage[]; outsideDiffScores?: number[]; }) { const message = @@ -141,6 +143,7 @@ class ScaleAdjustOutputRejectedError extends Error { this.name = "ScaleAdjustOutputRejectedError"; this.reason = params.reason; this.diffScores = params.diffScores; + this.images = params.images; this.outsideDiffScores = params.outsideDiffScores; } } @@ -1241,6 +1244,7 @@ async function applyScaleAdjustVerificationToImages(params: { ? "outside-frame-changed" : "no-effective-scale-change", diffScores: selected.changeDiffScores, + images: [selected.cleanedImage || selected.image], outsideDiffScores: selected.outsideDiffScores, }); } @@ -2513,8 +2517,9 @@ export async function generateCanvasImage( }); } - const scaleAdjustRejected = - caughtError instanceof ScaleAdjustOutputRejectedError; + const scaleAdjustRejection = + caughtError instanceof ScaleAdjustOutputRejectedError ? caughtError : null; + const scaleAdjustRejected = Boolean(scaleAdjustRejection); if (scaleAdjustRejected) { console.info("[Canvas Generate Image] Skip model health failure for scale adjust rejection:", { @@ -2523,7 +2528,6 @@ export async function generateCanvasImage( selectedModelId: selectedModel.model.modelId, error: caughtError instanceof Error ? caughtError.message : String(caughtError), }); - throw caughtError; } else { await recordAiModelHealthFailure({ model: selectedModel.model, @@ -2562,6 +2566,8 @@ export async function generateCanvasImage( const allowFailover = request.allowFailover !== false; const shouldFailover = shouldFailoverAiModelError(caughtError) || + (scaleAdjustRejected && + Boolean(debugMeta?.scaleAdjustPreferSameNameProviderFailover)) || (Boolean(debugMeta?.detailFixedModelApplied) && Boolean(caughtError)); const fallbackModel = allowFailover && shouldFailover ? findCanvasFailoverModel({ @@ -2599,5 +2605,22 @@ export async function generateCanvasImage( }); } + if (scaleAdjustRejection?.images?.length) { + console.warn("[Canvas Generate Image] Returning rejected scale adjust candidate because no fallback remains:", { + debugLabel, + imageCount: scaleAdjustRejection.images.length, + reason: scaleAdjustRejection.reason, + selectedModelRef: selectedModel.model.id, + selectedModelId: selectedModel.model.modelId, + ...debugMeta, + }); + return { + images: scaleAdjustRejection.images, + model: selectedModel.model.displayName, + modelRef: selectedModel.model.id, + prompt: resultPrompt, + }; + } + throw caughtError; }