/** Only adapters with an explicit rejection of the submission may use this. * Polling, result downloads and storage failures are not submission refusals. */ export class ImageSubmissionRejectedError extends Error { constructor(message: string, readonly status: number) { super(message); } } export class AgentImageGenerationError extends Error { constructor(message: string, readonly confirmedNoResult: boolean) { super(message); } } /** Preserve outcome evidence when replacing upstream diagnostics with safe UI text. */ export function agentImageGenerationError(error: unknown, mode: "auto" | "pinned") { const rejected = error instanceof ImageSubmissionRejectedError; const message = error instanceof Error ? error.message : ""; const suffix = mode === "pinned" ? "系统未自动切换。你希望切换生图模型,还是稍后重试?切换前请在模型选择器中选择其他模型或自动选择。" : "请稍后重试或联系管理员处理生图通道。"; if (rejected && /余额|insufficient.*(?:balance|credit)|credits? insufficient/i.test(message)) return new AgentImageGenerationError(`生图通道余额不足,本次未生成图片。${suffix}`, true); if (rejected && error.status === 429) return new AgentImageGenerationError(`生图通道额度不足或请求过多,本次未生成图片。${suffix}`, true); if (rejected && [401, 403].includes(error.status)) return new AgentImageGenerationError(`生图通道鉴权或权限未通过,本次未生成图片。${suffix}`, true); if (/content.?policy|moderation|safety|违规|敏感/i.test(message)) return new AgentImageGenerationError("当前图片内容无法处理,请调整描述或参考图后重试。", rejected); if ((error as { providerOutcomeUnknown?: boolean })?.providerOutcomeUnknown || /may still be running|仍在处理|outcome.unknown|timed out|timeout|超时|fetch failed|econnreset/i.test(message)) return new AgentImageGenerationError("图片任务的结果暂未确认,已保留任务记录,请先确认原任务结果,避免重复生成。", false); if (rejected) return new AgentImageGenerationError(`生图通道拒绝了本次请求,未生成图片。${suffix}`, true); return new AgentImageGenerationError(mode === "pinned" ? "你指定的生图模型本次未能完成,请稍后重试或手动更换模型;系统未自动切换。" : "暂时未能完成本次出图,请检查描述、参考图或稍后继续;已有结果会保留。", rejected); }