From e3eb16765206bebd02ab9126fbb90b29d0132c3d Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 24 Feb 2026 18:32:03 +0800 Subject: [PATCH] fix: harden detail plan image-link fallback and model send sync --- app/api/canvas/detail-plan/route.ts | 18 +++++++++++++++++- components/canvas/CanvasChatPanel.tsx | 12 ++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/app/api/canvas/detail-plan/route.ts b/app/api/canvas/detail-plan/route.ts index 371189ced..1d8274257 100644 --- a/app/api/canvas/detail-plan/route.ts +++ b/app/api/canvas/detail-plan/route.ts @@ -39,6 +39,19 @@ function isAbortError(error: unknown): boolean { ); } +function isReferenceImageDownloadError(error: unknown): boolean { + const target = error as { name?: unknown; message?: unknown }; + const name = String(target?.name || ""); + const message = String(target?.message || ""); + return ( + /AI_DownloadError/i.test(name) || + /Failed to download/i.test(message) || + /404\s*Not\s*Found/i.test(message) || + /403\s*Forbidden/i.test(message) || + /image.*download/i.test(message) + ); +} + function supportsVisionPlanning(model: { supportsVision?: boolean | null; capabilities?: unknown; @@ -1849,12 +1862,15 @@ export async function POST(request: Request) { if ( isAbortError(error) || /invalid scheme/i.test(message) || + isReferenceImageDownloadError(error) || /operationtimeouterror|timed out|timeout/i.test(message) ) { console.error("[Canvas Detail Plan] Primary planning aborted, fallback applied:", error); const fallbackReason = /invalid scheme/i.test(message) ? "规划模型图片输入协议不兼容,已回退到稳定分镜模板。" - : "规划模型调用超时,已自动回退到稳定分镜模板。"; + : isReferenceImageDownloadError(error) + ? "参考图链接不可访问(404/下载失败),已自动忽略参考图并回退稳定分镜模板。" + : "规划模型调用超时,已自动回退到稳定分镜模板。"; return NextResponse.json({ success: true, data: { diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index 7e1dfb0d0..e3adfbe4a 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -6450,14 +6450,18 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF }} disabled={isDetailGenerating} className={cn( - "rounded-lg border px-3 py-2 text-left transition-colors", + "rounded-lg border px-3 py-2 text-left transition-all duration-150", isDetailGenerating && "cursor-not-allowed opacity-60", selected - ? "border-primary/50 bg-primary/10 text-primary" - : "border-border/50 bg-background text-muted-foreground hover:border-primary/30 hover:text-foreground" + ? "border-[#5b7cff] bg-[#eef3ff] text-[#2f57d8] shadow-[0_0_0_1px_rgba(91,124,255,0.28)]" + : "border-border/60 bg-background text-muted-foreground hover:border-[#9fb3ff] hover:bg-[#f8faff] hover:text-foreground" )} + aria-pressed={selected} > -
{option.label}
+
+
{option.label}
+ {selected ? : null} +
{option.description}