mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-04-25 11:18:22 +00:00
fix(frontend): route agent checks to gateway (#1572)
* fix(frontend): route agent checks to gateway * fix(frontend): proxy langgraph requests locally * fix(frontend): keep zh-CN text readable * fix(frontend): add exact local api rewrites * fix(frontend): support docker-safe internal rewrites * Update frontend/src/core/agents/api.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
4bb3c101a8
commit
9e3d484858
@ -100,6 +100,8 @@ services:
|
||||
- NODE_ENV=development
|
||||
- WATCHPACK_POLLING=true
|
||||
- CI=true
|
||||
- DEER_FLOW_INTERNAL_GATEWAY_BASE_URL=http://gateway:8001
|
||||
- DEER_FLOW_INTERNAL_LANGGRAPH_BASE_URL=http://langgraph:2024
|
||||
env_file:
|
||||
- ../frontend/.env
|
||||
networks:
|
||||
|
||||
@ -50,6 +50,8 @@ services:
|
||||
container_name: deer-flow-frontend
|
||||
environment:
|
||||
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
|
||||
- DEER_FLOW_INTERNAL_GATEWAY_BASE_URL=http://gateway:8001
|
||||
- DEER_FLOW_INTERNAL_LANGGRAPH_BASE_URL=http://langgraph:2024
|
||||
env_file:
|
||||
- ../frontend/.env
|
||||
networks:
|
||||
|
||||
@ -4,9 +4,51 @@
|
||||
*/
|
||||
import "./src/env.js";
|
||||
|
||||
function getInternalServiceURL(envKey, fallbackURL) {
|
||||
const configured = process.env[envKey]?.trim();
|
||||
return configured && configured.length > 0
|
||||
? configured.replace(/\/+$/, "")
|
||||
: fallbackURL;
|
||||
}
|
||||
|
||||
/** @type {import("next").NextConfig} */
|
||||
const config = {
|
||||
devIndicators: false,
|
||||
async rewrites() {
|
||||
const rewrites = [];
|
||||
const langgraphURL = getInternalServiceURL(
|
||||
"DEER_FLOW_INTERNAL_LANGGRAPH_BASE_URL",
|
||||
"http://127.0.0.1:2024",
|
||||
);
|
||||
const gatewayURL = getInternalServiceURL(
|
||||
"DEER_FLOW_INTERNAL_GATEWAY_BASE_URL",
|
||||
"http://127.0.0.1:8001",
|
||||
);
|
||||
|
||||
if (!process.env.NEXT_PUBLIC_LANGGRAPH_BASE_URL) {
|
||||
rewrites.push({
|
||||
source: "/api/langgraph",
|
||||
destination: langgraphURL,
|
||||
});
|
||||
rewrites.push({
|
||||
source: "/api/langgraph/:path*",
|
||||
destination: `${langgraphURL}/:path*`,
|
||||
});
|
||||
}
|
||||
|
||||
if (!process.env.NEXT_PUBLIC_BACKEND_BASE_URL) {
|
||||
rewrites.push({
|
||||
source: "/api/agents",
|
||||
destination: `${gatewayURL}/api/agents`,
|
||||
});
|
||||
rewrites.push({
|
||||
source: "/api/agents/:path*",
|
||||
destination: `${gatewayURL}/api/agents/:path*`,
|
||||
});
|
||||
}
|
||||
|
||||
return rewrites;
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
@ -16,7 +16,11 @@ import { ArtifactsProvider } from "@/components/workspace/artifacts";
|
||||
import { MessageList } from "@/components/workspace/messages";
|
||||
import { ThreadContext } from "@/components/workspace/messages/context";
|
||||
import type { Agent } from "@/core/agents";
|
||||
import { checkAgentName, getAgent } from "@/core/agents/api";
|
||||
import {
|
||||
AgentNameCheckError,
|
||||
checkAgentName,
|
||||
getAgent,
|
||||
} from "@/core/agents/api";
|
||||
import { useI18n } from "@/core/i18n/hooks";
|
||||
import { useThreadStream } from "@/core/threads/hooks";
|
||||
import { uuid } from "@/core/utils/uuid";
|
||||
@ -76,8 +80,16 @@ export default function NewAgentPage() {
|
||||
setNameError(t.agents.nameStepAlreadyExistsError);
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
setNameError(t.agents.nameStepCheckError);
|
||||
} catch (error) {
|
||||
if (error instanceof AgentNameCheckError) {
|
||||
setNameError(
|
||||
error.reason === "backend_unreachable"
|
||||
? t.agents.nameStepCheckError
|
||||
: error.message,
|
||||
);
|
||||
} else {
|
||||
setNameError(t.agents.nameStepCheckError);
|
||||
}
|
||||
return;
|
||||
} finally {
|
||||
setIsCheckingName(false);
|
||||
|
||||
@ -2,6 +2,18 @@ import { getBackendBaseURL } from "@/core/config";
|
||||
|
||||
import type { Agent, CreateAgentRequest, UpdateAgentRequest } from "./types";
|
||||
|
||||
const BACKEND_UNAVAILABLE_STATUSES = new Set([502, 503, 504]);
|
||||
|
||||
export class AgentNameCheckError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly reason: "backend_unreachable" | "request_failed",
|
||||
) {
|
||||
super(message);
|
||||
this.name = "AgentNameCheckError";
|
||||
}
|
||||
}
|
||||
|
||||
export async function listAgents(): Promise<Agent[]> {
|
||||
const res = await fetch(`${getBackendBaseURL()}/api/agents`);
|
||||
if (!res.ok) throw new Error(`Failed to load agents: ${res.statusText}`);
|
||||
@ -54,13 +66,29 @@ export async function deleteAgent(name: string): Promise<void> {
|
||||
export async function checkAgentName(
|
||||
name: string,
|
||||
): Promise<{ available: boolean; name: string }> {
|
||||
const res = await fetch(
|
||||
`${getBackendBaseURL()}/api/agents/check?name=${encodeURIComponent(name)}`,
|
||||
);
|
||||
let res: Response;
|
||||
try {
|
||||
res = await fetch(
|
||||
`${getBackendBaseURL()}/api/agents/check?name=${encodeURIComponent(name)}`,
|
||||
);
|
||||
} catch {
|
||||
throw new AgentNameCheckError(
|
||||
"Could not reach the DeerFlow backend.",
|
||||
"backend_unreachable",
|
||||
);
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
const err = (await res.json().catch(() => ({}))) as { detail?: string };
|
||||
throw new Error(
|
||||
if (BACKEND_UNAVAILABLE_STATUSES.has(res.status)) {
|
||||
throw new AgentNameCheckError(
|
||||
"Could not reach the DeerFlow backend.",
|
||||
"backend_unreachable",
|
||||
);
|
||||
}
|
||||
throw new AgentNameCheckError(
|
||||
err.detail ?? `Failed to check agent name: ${res.statusText}`,
|
||||
"request_failed",
|
||||
);
|
||||
}
|
||||
return res.json() as Promise<{ available: boolean; name: string }>;
|
||||
|
||||
@ -194,7 +194,8 @@ export const enUS: Translations = {
|
||||
nameStepInvalidError:
|
||||
"Invalid name — use only letters, digits, and hyphens",
|
||||
nameStepAlreadyExistsError: "An agent with this name already exists",
|
||||
nameStepCheckError: "Could not verify name availability — please try again",
|
||||
nameStepCheckError:
|
||||
"Could not reach the DeerFlow backend to verify name availability. Start the backend or set NEXT_PUBLIC_BACKEND_BASE_URL, then try again.",
|
||||
nameStepBootstrapMessage:
|
||||
"The new custom agent name is {name}. Let's bootstrap it's **SOUL**.",
|
||||
agentCreated: "Agent created!",
|
||||
|
||||
@ -183,7 +183,8 @@ export const zhCN: Translations = {
|
||||
nameStepContinue: "继续",
|
||||
nameStepInvalidError: "名称无效,只允许字母、数字和连字符",
|
||||
nameStepAlreadyExistsError: "已存在同名智能体",
|
||||
nameStepCheckError: "无法验证名称可用性,请稍后重试",
|
||||
nameStepCheckError:
|
||||
"无法连接 DeerFlow 后端来验证名称是否可用。请先启动后端,或配置 NEXT_PUBLIC_BACKEND_BASE_URL,然后再重试。",
|
||||
nameStepBootstrapMessage:
|
||||
"新智能体的名称是 {name},现在开始为它生成 **SOUL**。",
|
||||
agentCreated: "智能体已创建!",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user