From 523e4281fc5ea96bcdce9cbe72cf677709fd8bbc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:53:19 +0000 Subject: [PATCH] refactor: address code review feedback - fix normalizeApiBase regex, improve error code propagation Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- persona-studio/backend/routes/apikey.js | 17 +++++++++++------ persona-studio/frontend/chat.js | 4 +++- persona-studio/frontend/index.html | 8 ++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/persona-studio/backend/routes/apikey.js b/persona-studio/backend/routes/apikey.js index c88b186a..56d6b8b3 100644 --- a/persona-studio/backend/routes/apikey.js +++ b/persona-studio/backend/routes/apikey.js @@ -81,12 +81,16 @@ function fetchModels(apiBase, apiKey, timeoutMs) { }); req.on('error', (err) => { - reject(new Error('API Base 不可访问: ' + err.message)); + const wrapped = new Error('API Base 不可访问: ' + err.message); + wrapped.code = err.code; + reject(wrapped); }); req.on('timeout', () => { req.destroy(); - reject(new Error('API Base 不可访问(请求超时)')); + const err = new Error('API Base 不可访问(请求超时)'); + err.code = 'ETIMEDOUT'; + reject(err); }); req.end(); @@ -230,14 +234,15 @@ router.post('/detect-models', async (req, res) => { }); } catch (err) { const errMsg = err.message || '模型检测失败'; + const errCode = err.code || ''; let code = 'DETECT_FAILED'; - // 区分 DNS / 网络 / 超时错误 - if (/ENOTFOUND|getaddrinfo/.test(errMsg)) { + // 区分 DNS / 网络 / 超时错误(优先使用 Node.js 错误码) + if (errCode === 'ENOTFOUND' || errCode === 'EAI_AGAIN' || /ENOTFOUND|getaddrinfo/.test(errMsg)) { code = 'DNS_ERROR'; - } else if (/ECONNREFUSED|ECONNRESET|EHOSTUNREACH|ENETUNREACH|socket hang up/.test(errMsg)) { + } else if (errCode === 'ECONNREFUSED' || errCode === 'ECONNRESET' || errCode === 'EHOSTUNREACH' || errCode === 'ENETUNREACH' || /ECONNREFUSED|ECONNRESET|EHOSTUNREACH|ENETUNREACH|socket hang up/.test(errMsg)) { code = 'NETWORK_ERROR'; - } else if (/timeout|ETIMEDOUT|请求超时/.test(errMsg)) { + } else if (errCode === 'ETIMEDOUT' || errCode === 'ESOCKETTIMEDOUT' || /timeout|ETIMEDOUT/.test(errMsg)) { code = 'TIMEOUT'; } diff --git a/persona-studio/frontend/chat.js b/persona-studio/frontend/chat.js index 87029186..a365219e 100644 --- a/persona-studio/frontend/chat.js +++ b/persona-studio/frontend/chat.js @@ -195,7 +195,9 @@ async function streamApiKeyReply(text) { if (d === '[DONE]') continue; try { var parsed = JSON.parse(d); - var delta = parsed.choices && parsed.choices[0] && parsed.choices[0].delta && parsed.choices[0].delta.content; + var delta = parsed.choices && parsed.choices[0] + && parsed.choices[0].delta + && parsed.choices[0].delta.content; if (delta) { full += delta; streamEl.textContent = full; diff --git a/persona-studio/frontend/index.html b/persona-studio/frontend/index.html index d25d6ab4..eb8c080d 100644 --- a/persona-studio/frontend/index.html +++ b/persona-studio/frontend/index.html @@ -101,7 +101,7 @@ */ function normalizeApiBase(base) { var normalized = base.replace(/\/+$/, ''); - if (!normalized.match(/\/v\d+\b/) && !normalized.endsWith('/openai')) { + if (!normalized.match(/\/v\d+(\/|$)/) && !normalized.endsWith('/openai')) { normalized += '/v1'; } return normalized; @@ -185,12 +185,12 @@ /* 构建探测列表:用户端点优先,然后已知端点 */ var candidates = []; if (apiBase) { - var userNorm = normalizeApiBase(apiBase); - candidates.push({ label: apiBase, base: userNorm }); + var normalizedUserBase = normalizeApiBase(apiBase); + candidates.push({ label: apiBase, base: normalizedUserBase }); } for (var i = 0; i < KNOWN_ENDPOINTS.length; i++) { var ep = KNOWN_ENDPOINTS[i]; - if (!apiBase || ep.base !== normalizeApiBase(apiBase)) { + if (!apiBase || ep.base !== normalizedUserBase) { candidates.push(ep); } }