diff --git a/frontend/src/app/workspace/agents/new/page.tsx b/frontend/src/app/workspace/agents/new/page.tsx index f5b2e6070..d15d97ff9 100644 --- a/frontend/src/app/workspace/agents/new/page.tsx +++ b/frontend/src/app/workspace/agents/new/page.tsx @@ -33,6 +33,7 @@ import { ThreadContext } from "@/components/workspace/messages/context"; import type { Agent } from "@/core/agents"; import { AgentNameCheckError, + AgentsApiDisabledError, checkAgentName, createAgent, getAgent, @@ -154,7 +155,9 @@ export default function NewAgentPage() { return; } } catch (err) { - if ( + if (err instanceof AgentsApiDisabledError) { + setNameError(t.agents.nameStepApiDisabledError); + } else if ( err instanceof AgentNameCheckError && err.reason === "backend_unreachable" ) { @@ -175,6 +178,10 @@ export default function NewAgentPage() { soul: "", }); } catch (err) { + if (err instanceof AgentsApiDisabledError) { + setNameError(t.agents.nameStepApiDisabledError); + return; + } setNameError( getCreateAgentErrorMessage( err, @@ -197,6 +204,7 @@ export default function NewAgentPage() { nameInput, sendMessage, t.agents.nameStepAlreadyExistsError, + t.agents.nameStepApiDisabledError, t.agents.nameStepNetworkError, t.agents.nameStepBootstrapMessage, t.agents.nameStepCheckError, diff --git a/frontend/src/core/agents/api.ts b/frontend/src/core/agents/api.ts index 062a14b24..5cfc40466 100644 --- a/frontend/src/core/agents/api.ts +++ b/frontend/src/core/agents/api.ts @@ -15,6 +15,17 @@ export class AgentNameCheckError extends Error { } } +export class AgentsApiDisabledError extends Error { + constructor(message: string) { + super(message); + this.name = "AgentsApiDisabledError"; + } +} + +function isAgentsApiDisabledDetail(detail: string | undefined): boolean { + return typeof detail === "string" && detail.includes("agents_api.enabled"); +} + export async function listAgents(): Promise { const res = await fetch(`${getBackendBaseURL()}/api/agents`); if (!res.ok) throw new Error(`Failed to load agents: ${res.statusText}`); @@ -36,6 +47,9 @@ export async function createAgent(request: CreateAgentRequest): Promise { }); if (!res.ok) { const err = (await res.json().catch(() => ({}))) as { detail?: string }; + if (isAgentsApiDisabledDetail(err.detail)) { + throw new AgentsApiDisabledError(err.detail!); + } throw new Error(err.detail ?? `Failed to create agent: ${res.statusText}`); } return res.json() as Promise; @@ -81,6 +95,9 @@ export async function checkAgentName( if (!res.ok) { const err = (await res.json().catch(() => ({}))) as { detail?: string }; + if (isAgentsApiDisabledDetail(err.detail)) { + throw new AgentsApiDisabledError(err.detail!); + } if (BACKEND_UNAVAILABLE_STATUSES.has(res.status)) { throw new AgentNameCheckError( "Could not reach the DeerFlow backend.", diff --git a/frontend/src/core/i18n/locales/en-US.ts b/frontend/src/core/i18n/locales/en-US.ts index 6c6bb1525..615ce808e 100644 --- a/frontend/src/core/i18n/locales/en-US.ts +++ b/frontend/src/core/i18n/locales/en-US.ts @@ -204,6 +204,8 @@ export const enUS: Translations = { nameStepNetworkError: "Network request failed — check your network or backend connection", nameStepCheckError: "Could not verify name availability — please try again", + nameStepApiDisabledError: + "Custom agent management is not enabled on this server. Please contact your administrator.", nameStepBootstrapMessage: "The new custom agent name is {name}. Let's bootstrap it's **SOUL**.", save: "Save agent", diff --git a/frontend/src/core/i18n/locales/types.ts b/frontend/src/core/i18n/locales/types.ts index a4fa38dcb..b57c4be46 100644 --- a/frontend/src/core/i18n/locales/types.ts +++ b/frontend/src/core/i18n/locales/types.ts @@ -141,6 +141,7 @@ export interface Translations { nameStepAlreadyExistsError: string; nameStepNetworkError: string; nameStepCheckError: string; + nameStepApiDisabledError: string; nameStepBootstrapMessage: string; save: string; saving: string; diff --git a/frontend/src/core/i18n/locales/zh-CN.ts b/frontend/src/core/i18n/locales/zh-CN.ts index 2b2372b97..544f72505 100644 --- a/frontend/src/core/i18n/locales/zh-CN.ts +++ b/frontend/src/core/i18n/locales/zh-CN.ts @@ -192,6 +192,8 @@ export const zhCN: Translations = { nameStepAlreadyExistsError: "已存在同名智能体", nameStepNetworkError: "网络请求失败,请检查网络或后端连接", nameStepCheckError: "无法验证名称可用性,请稍后重试", + nameStepApiDisabledError: + "服务器未开启自定义智能体管理功能,请联系管理员。", nameStepBootstrapMessage: "新智能体的名称是 {name},现在开始为它生成 **SOUL**。", save: "保存智能体",