From 54700b3ebb8efe996c04cd535bdd3add63beb727 Mon Sep 17 00:00:00 2001 From: 134 Date: Wed, 21 Oct 2026 10:26:59 +0800 Subject: [PATCH] fix(agent): retain image fault records and show actionable recovery messages --- lib/canvas/generate-image.ts | 11 ++++++++++- .../canvas-agent-runtime-image-failover.test.ts | 7 +++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/canvas/generate-image.ts b/lib/canvas/generate-image.ts index 2ae709c20..ccbee4ff3 100644 --- a/lib/canvas/generate-image.ts +++ b/lib/canvas/generate-image.ts @@ -5700,7 +5700,7 @@ export async function generateCanvasImage( selectedModelId: selectedModel.model.modelId, error: caughtError instanceof Error ? caughtError.message : String(caughtError), }); - } else if (request.agentImageMode === "auto") { + } else if (request.agentImageMode) { const failure = agentImageFailurePolicy(caughtError); if (failure.pause) await agentImageCircuitStore.fail(selectedModel, failure.pause); } else { @@ -5867,5 +5867,14 @@ export async function generateCanvasImage( throw caughtError; } + if (request.agentImageMode) { + const message = String((caughtError as { message?: string })?.message || ""); + if (/content.?policy|moderation|safety|违规|敏感/i.test(message)) throw new Error("当前图片内容无法处理,请调整描述或参考图后重试。"); + if ((caughtError as { providerOutcomeUnknown?: boolean })?.providerOutcomeUnknown || /may still be running|仍在处理|outcome.unknown|timed out|timeout|超时|fetch failed|econnreset/i.test(message)) + throw new Error("图片任务的结果暂未确认,已保留任务记录,请先确认原任务结果,避免重复生成。"); + throw new Error(request.agentImageMode === "pinned" + ? "你指定的生图模型本次未能完成,请稍后重试或手动更换模型;系统未自动切换。" + : "当前图片通道暂时未能完成任务,已尝试可用的备用模型,请稍后继续;已有结果会保留。"); + } throw caughtError; } diff --git a/tests/routes/canvas-agent-runtime-image-failover.test.ts b/tests/routes/canvas-agent-runtime-image-failover.test.ts index f1de27324..ed6b665c3 100644 --- a/tests/routes/canvas-agent-runtime-image-failover.test.ts +++ b/tests/routes/canvas-agent-runtime-image-failover.test.ts @@ -76,3 +76,10 @@ test("provider adapters that include HTTP status or quota only in their message } expect(agentImageFailurePolicy(new Error("invalid input (HTTP 400)")).retry).toBe(false); }); + + +test("exhausted automatic channels and pinned failures show useful messages without provider diagnostics", async () => { + const h = harness({ generate: () => { throw Object.assign(new Error("provider-internal-trace HTTP 503"), { status: 503 }); } }); + await expect(h.generate(h.request)).rejects.toThrow("已尝试可用的备用模型"); + await expect(h.generate({ ...h.request, agentImageMode: "pinned" })).rejects.toThrow("系统未自动切换"); +});