|
|
@@ -385,6 +385,61 @@ function buildModelCandidates(args: {
|
|
|
return candidates;
|
|
|
}
|
|
|
|
|
|
+function formatServiceProbeError(args: {
|
|
|
+ readonly service: string;
|
|
|
+ readonly label?: string;
|
|
|
+ readonly baseUrl: string;
|
|
|
+ readonly model?: string;
|
|
|
+ readonly apiFormat?: "chat" | "responses";
|
|
|
+ readonly stream?: boolean;
|
|
|
+ readonly error: string;
|
|
|
+}): string {
|
|
|
+ const rawDetail = args.error
|
|
|
+ .replace(/\n\s*\(baseUrl:[\s\S]*?\)$/m, "")
|
|
|
+ .trim();
|
|
|
+ const upstreamDetail = rawDetail.includes("上游详情:")
|
|
|
+ ? rawDetail
|
|
|
+ : "";
|
|
|
+ const context = [
|
|
|
+ `服务商:${args.label ?? args.service}`,
|
|
|
+ `测试模型:${args.model ?? "未确定"}`,
|
|
|
+ `协议:${args.apiFormat === "responses" ? "Responses" : "Chat / Completions"}${typeof args.stream === "boolean" ? `,${args.stream ? "流式" : "非流式"}` : ""}`,
|
|
|
+ `Base URL:${args.baseUrl}`,
|
|
|
+ ].join("\n");
|
|
|
+
|
|
|
+ if (args.service === "google") {
|
|
|
+ return [
|
|
|
+ "Google Gemini 测试连接失败。",
|
|
|
+ context,
|
|
|
+ "",
|
|
|
+ "请优先检查:",
|
|
|
+ "1. API Key 是否来自 Google AI Studio 的 Gemini API key,而不是 OAuth、Vertex AI 或其它 Google 服务凭据。",
|
|
|
+ "2. 该 key 所属项目是否已启用 Gemini API,并且没有被限制到其它 API、来源或服务。",
|
|
|
+ "3. 当前地区/账号是否允许访问 Gemini API。",
|
|
|
+ "4. 如果 key 曾经泄露,请在 AI Studio 重新生成后再保存。",
|
|
|
+ upstreamDetail ? `\n上游返回:${upstreamDetail}` : "",
|
|
|
+ ].filter(Boolean).join("\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (args.service === "moonshot" || args.service === "kimiCodingPlan") {
|
|
|
+ return [
|
|
|
+ `${args.label ?? args.service} 测试连接失败。`,
|
|
|
+ context,
|
|
|
+ "",
|
|
|
+ "请优先检查模型是否可用,以及 kimi-k2.x 这类模型是否需要 temperature=1。",
|
|
|
+ rawDetail ? `\n上游返回:${rawDetail}` : "",
|
|
|
+ ].filter(Boolean).join("\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ `${args.label ?? args.service} 测试连接失败。`,
|
|
|
+ context,
|
|
|
+ "",
|
|
|
+ "请检查 API Key、模型可用性、账号额度,以及协议类型是否匹配该服务商。",
|
|
|
+ rawDetail ? `\n上游返回:${rawDetail}` : "",
|
|
|
+ ].filter(Boolean).join("\n");
|
|
|
+}
|
|
|
+
|
|
|
async function fetchModelsFromServiceBaseUrl(
|
|
|
serviceId: string,
|
|
|
baseUrl: string,
|
|
|
@@ -513,7 +568,15 @@ async function probeServiceCapabilities(args: {
|
|
|
modelsSource: discoveredModels.length > 0 ? "api" : "fallback",
|
|
|
};
|
|
|
} catch (error) {
|
|
|
- lastError = error instanceof Error ? error.message : String(error);
|
|
|
+ lastError = formatServiceProbeError({
|
|
|
+ service: baseService,
|
|
|
+ label: endpoint?.label ?? preset?.label,
|
|
|
+ baseUrl: args.baseUrl,
|
|
|
+ model,
|
|
|
+ apiFormat: plan.apiFormat,
|
|
|
+ stream: plan.stream,
|
|
|
+ error: error instanceof Error ? error.message : String(error),
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
}
|