fix: surface chat stream provider failures
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-13 17:07:39 +08:00
parent 810b530eb0
commit 161c04e23e

View File

@ -1192,6 +1192,46 @@ function getDirectAgentToolErrorMessage(
}
}
function getChatStreamErrorMessage(error: unknown): string {
const rawMessage =
error instanceof Error ? String(error.message || "").trim() : String(error || "").trim();
const normalized = rawMessage.toLowerCase();
if (
normalized.includes("token quota is not enough") ||
normalized.includes("pre_consume_token_quota_failed") ||
normalized.includes("quota is not enough")
) {
return "当前对话模型额度不足,请切换其他模型,或联系管理员补充该模型额度。";
}
if (
normalized.includes("timeout") ||
normalized.includes("timed out") ||
normalized.includes("body timeout")
) {
return "当前对话模型响应超时,请重试,或切换到其他可用模型。";
}
if (rawMessage) {
return `当前对话暂时失败:${rawMessage}`;
}
return "当前对话暂时失败,请重试或切换其他模型。";
}
function normalizeAssistantPartsForPersistence(parts: Array<Record<string, any>> | undefined) {
const safeParts = Array.isArray(parts) ? parts.filter(Boolean) : [];
return safeParts.filter((part) => {
const partType = String(part?.type || "").trim();
if (!partType) return false;
if (partType === "data-keepalive" || partType === "step-start" || partType === "step-finish") {
return false;
}
return true;
});
}
function buildAgentToolImageMarkdown(params: {
originalUrl: string;
thumbnailUrl?: string | null;
@ -9187,11 +9227,19 @@ export async function POST(request: Request) {
},
});
result.consumeStream();
result.consumeStream({
onError: (error) => {
console.error("[Chat API] streamText consume error:", error);
},
});
dataStream.merge(
result.toUIMessageStream({
sendReasoning: true,
onError: (error) => {
console.error("[Chat API] streamText ui stream error:", error);
return getChatStreamErrorMessage(error);
},
})
);
} finally {
@ -9203,11 +9251,39 @@ export async function POST(request: Request) {
onFinish: async ({ messages }) => {
stopStreamKeepalive?.();
stopStreamKeepalive = null;
await saveMessages({
messages: messages.map((currentMessage) => ({
const messagesToPersist: Array<{
id: string;
role: string;
parts: unknown;
createdAt: Date;
attachments: unknown;
chatId: string;
videoStorageStatus: null;
temporaryVideoUrl: null;
permanentVideoUrl: null;
archivedAt: null;
videoMetadata: null;
}> = [];
for (const currentMessage of messages) {
const normalizedParts =
currentMessage.role === "assistant"
? normalizeAssistantPartsForPersistence(
currentMessage.parts as Array<Record<string, any>> | undefined,
)
: currentMessage.parts;
if (
currentMessage.role === "assistant" &&
(!Array.isArray(normalizedParts) || normalizedParts.length === 0)
) {
continue;
}
messagesToPersist.push({
id: currentMessage.id,
role: currentMessage.role,
parts: currentMessage.parts,
parts: normalizedParts,
createdAt: new Date(),
attachments: [],
chatId: id,
@ -9216,8 +9292,14 @@ export async function POST(request: Request) {
permanentVideoUrl: null,
archivedAt: null,
videoMetadata: null,
})),
});
});
}
if (messagesToPersist.length > 0) {
await saveMessages({
messages: messagesToPersist,
});
}
// 检测助手消息中是否包含视频,如果有则立即标记并归档到永久存储
for (const msg of messages) {