mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-06-10 17:35:57 +00:00
fix(frontend): surface backend detail when agent name check fails (#3048)
* fix(frontend): surface backend detail when agent name check fails The new-agent page caught AgentNameCheckError but only branched on reason === "backend_unreachable". Everything else (notably the 422 "Invalid agent name '...'. Must match ^[A-Za-z0-9-]+$" response from GET /api/agents/check when the user submits a name with disallowed characters — trailing space, dot, Chinese, invisible whitespace from copy-paste) fell through to the generic fallback "Could not verify name availability — please try again", swallowing the detail that already told the user exactly what to fix. Add a request_failed branch that surfaces err.message (which checkAgentName already populates from the backend's detail at core/agents/api.ts). The disabled / backend_unreachable / unknown- error paths are unchanged. Pin the contract with unit tests covering: 200 success, fetch rejection, 502/503/504 network errors, agents_api disabled detail, 422 validation detail carried verbatim, statusText fallback when detail is absent, and a regression guard against misclassifying a 422 as agents_api disabled. Closes #3041 * fix(frontend): localise the error prefix when surfacing backend detail The previous commit surfaced the backend's raw `err.message` on the new-agent page when the name check failed. The detail itself is English (backend's `_validate_agent_name` text, any 5xx business message, etc.) and dropping it bare into a zh-CN page produced a jarring English-among-Chinese line that didn't match neighbouring strings like "已存在同名智能体" / "无法验证名称可用性". Add `nameStepCheckErrorWithDetail` as a templated string ("Name check failed: {detail}" / "名称校验失败:{detail}"), mirroring the existing `nameStepBootstrapMessage` `{name}` template pattern. The page wraps `err.message` in it when present and falls back to the plain `nameStepCheckError` when the detail is empty. Rendered output (verified locally with a Console fetch mock that returns 500 + detail): zh-CN: 名称校验失败:Database connection lost: SQLAlchemy connection pool exhausted (max 5 connections, all in use) en-US: Name check failed: Database connection lost: SQLAlchemy connection pool exhausted (max 5 connections, all in use) The localised prefix tells the user *what operation* failed; the raw detail tells them *why*. Translating the detail itself would be lossy (any unbounded backend string would need a translation table) and would break the debuggability the previous commit delivered. Refs #3041 * fix(frontend): distinguish backend detail from generated fallback in AgentNameCheckError Addresses Copilot's review on #3048: the previous commits keyed off `err.message`, but `checkAgentName` substitutes a generated fallback string ("Failed to check agent name: ${statusText}") when the backend sent no detail. That guaranteed `err.message` was always truthy, made the `nameStepCheckError` fallback branch unreachable in practice, and could surface awkward strings like "名称校验失败:Failed to check agent name: Bad Gateway" in the UI. Add an explicit `detail: string | null` field to AgentNameCheckError. `checkAgentName` populates it only when the backend response actually carried a string `detail` (defensive guard against the dict-shaped detail that other deer-flow endpoints use for typed error codes). The new-agent page now selects on `err.detail` instead of `err.message` so the localised fallback wins when no real detail exists. Also fix the prettier formatting that broke lint-frontend CI on the previous push. Test changes: - The 422 carry-through test now asserts both `detail` and `message` hold the backend string verbatim. - A new "falls back to statusText in message but leaves detail null" test pins the contract that no real detail ⇒ no UI surface leak. - A new "treats non-string detail as null" test guards against future backend schema drift toward dict-shaped detail. Refs #3041 #3048
This commit is contained in:
@@ -9,6 +9,15 @@ export class AgentNameCheckError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly reason: "backend_unreachable" | "request_failed",
|
||||
/**
|
||||
* Raw backend `detail` string when the failure came from a backend
|
||||
* response carrying one. `null` when no detail was provided (e.g.
|
||||
* network-layer failure, empty response body, unparseable body) — in
|
||||
* which case `message` is a generated fallback like "Failed to check
|
||||
* agent name: Bad Gateway" and the UI should prefer its own localized
|
||||
* fallback instead of surfacing the generated string.
|
||||
*/
|
||||
public readonly detail: string | null = null,
|
||||
) {
|
||||
super(message);
|
||||
this.name = "AgentNameCheckError";
|
||||
@@ -104,9 +113,11 @@ export async function checkAgentName(
|
||||
"backend_unreachable",
|
||||
);
|
||||
}
|
||||
const backendDetail = typeof err.detail === "string" ? err.detail : null;
|
||||
throw new AgentNameCheckError(
|
||||
err.detail ?? `Failed to check agent name: ${res.statusText}`,
|
||||
backendDetail ?? `Failed to check agent name: ${res.statusText}`,
|
||||
"request_failed",
|
||||
backendDetail,
|
||||
);
|
||||
}
|
||||
return res.json() as Promise<{ available: boolean; name: string }>;
|
||||
|
||||
@@ -204,6 +204,7 @@ export const enUS: Translations = {
|
||||
nameStepNetworkError:
|
||||
"Network request failed — check your network or backend connection",
|
||||
nameStepCheckError: "Could not verify name availability — please try again",
|
||||
nameStepCheckErrorWithDetail: "Name check failed: {detail}",
|
||||
nameStepApiDisabledError:
|
||||
"Custom agent management is not enabled on this server. Please contact your administrator.",
|
||||
nameStepBootstrapMessage:
|
||||
|
||||
@@ -141,6 +141,7 @@ export interface Translations {
|
||||
nameStepAlreadyExistsError: string;
|
||||
nameStepNetworkError: string;
|
||||
nameStepCheckError: string;
|
||||
nameStepCheckErrorWithDetail: string;
|
||||
nameStepApiDisabledError: string;
|
||||
nameStepBootstrapMessage: string;
|
||||
save: string;
|
||||
|
||||
@@ -192,6 +192,7 @@ export const zhCN: Translations = {
|
||||
nameStepAlreadyExistsError: "已存在同名智能体",
|
||||
nameStepNetworkError: "网络请求失败,请检查网络或后端连接",
|
||||
nameStepCheckError: "无法验证名称可用性,请稍后重试",
|
||||
nameStepCheckErrorWithDetail: "名称校验失败:{detail}",
|
||||
nameStepApiDisabledError:
|
||||
"服务器未开启自定义智能体管理功能,请联系管理员。",
|
||||
nameStepBootstrapMessage:
|
||||
|
||||
Reference in New Issue
Block a user