diff --git a/lib/request-error.ts b/lib/request-error.ts index d78ee2fca..8adadffbe 100644 --- a/lib/request-error.ts +++ b/lib/request-error.ts @@ -293,7 +293,11 @@ export function getRequestFailureDetails( if (/AOS结果下载超时/.test(text)) { return detail("RMBG_RESULT_DOWNLOAD_TIMEOUT", "抠图已完成,但结果图片下载超时。", "请联系管理员按请求编号取回原任务结果,避免重复抠图。", "unknown"); } - if ((isRecord(error) && (error.providerOutcomeUnknown === true || ["AbortError", "TimeoutError"].includes(String(error.name)))) || /结果(?:尚)?未确认|结果暂未确认|request_outcome_unknown|任务执行中断|may still be running|operation was aborted/i.test(text)) { + const errorName = isRecord(error) ? String(error.name || "") : ""; + if (["AbortError", "TimeoutError"].includes(errorName) || /operation was aborted/i.test(text)) { + return detail("RESULT_UNCONFIRMED", errorName === "TimeoutError" ? "请求等待超时,任务结果尚未确认。" : "本次请求连接已中止,任务结果尚未确认。", "请先核对原任务或历史记录;持续没有结果时联系管理员,避免重复生成。", "unknown"); + } + if ((isRecord(error) && error.providerOutcomeUnknown === true) || /结果(?:尚)?未确认|结果暂未确认|request_outcome_unknown|任务执行中断|may still be running/i.test(text)) { return detail("RESULT_UNCONFIRMED", "任务结果尚未确认,可能仍在处理。", "请先查看原任务或历史记录;持续没有结果时联系管理员,避免重复生成。", "unknown"); } if (isProviderBalanceError(error)) { diff --git a/tests/routes/image-provider-error-classification.test.ts b/tests/routes/image-provider-error-classification.test.ts index e793f1b2e..59bc7dba5 100644 --- a/tests/routes/image-provider-error-classification.test.ts +++ b/tests/routes/image-provider-error-classification.test.ts @@ -81,6 +81,9 @@ test("aborts and unconfirmed fallback results cannot start another paid generati expect(health.shouldFailoverAiModelError(error)).toBe(false); } expect(health.shouldFailoverAiModelError(new Error("Service unavailable (HTTP 503)"))).toBe(true); + expect(getRequestFailureDetails(Object.assign(new Error("This operation was aborted"), { name: "AbortError" })).message).toContain("连接已中止"); + expect(getRequestFailureDetails("This operation was aborted").message).toContain("连接已中止"); + expect(getRequestFailureDetails(Object.assign(new Error("timed out"), { name: "TimeoutError" })).message).toContain("等待超时"); }); test("the provider submits once when an HTTP 524 request cannot be located", async () => { diff --git a/tests/routes/zcode-agent-task.test.ts b/tests/routes/zcode-agent-task.test.ts index 669bd4c86..c90995fe9 100644 --- a/tests/routes/zcode-agent-task.test.ts +++ b/tests/routes/zcode-agent-task.test.ts @@ -53,6 +53,7 @@ test("an unconfirmed paid tool stops the planner and immediately preserves the r expect(submissions).toBe(1); expect(emitted).toEqual([]); expect(snapshot.message).toContain("结果尚未确认"); + expect(snapshot.message).toContain("连接已中止"); expect(snapshot.message).toContain("不要换模型、新建对话或重新提交"); expect(snapshot.message).toContain(ports.runId); ports.native = async () => { throw new Error("must not start a new attempt"); };