diff --git a/frontend/src/components/pages/AssistantPage.tsx b/frontend/src/components/pages/AssistantPage.tsx index ecf0fb8..a45492a 100644 --- a/frontend/src/components/pages/AssistantPage.tsx +++ b/frontend/src/components/pages/AssistantPage.tsx @@ -5,7 +5,6 @@ import { Brain, Check, Copy, - Database, MessageSquareText, MoreHorizontal, Pencil, @@ -81,17 +80,11 @@ import type { AssistantForm } from "@/components/assistant-editor/types"; import { PromptEditor } from "@/components/assistant-editor/prompt-editor"; import { WorkflowPage } from "@/components/assistant-editor/workflow-page"; -type FastGptForm = { - name: string; - agent: string; - asr: string; - voice: string; - enableInterrupt: boolean; - turnConfig: TurnConfig; -}; +type AgentPlatform = "dify" | "fastgpt"; -type DifyForm = { +type AgentPlatformForm = { name: string; + platform: AgentPlatform; agent: string; asr: string; voice: string; @@ -113,6 +106,7 @@ type OpenCodeForm = { }; type AssistantType = "提示词" | "工作流" | "Dify" | "FastGPT" | "OpenCode"; +type BuildMethod = "提示词" | "工作流" | "智能体平台" | "OpenCode"; const assistantTypes: AssistantType[] = [ "提示词", @@ -138,19 +132,20 @@ const typeToLabel: Record = { fastgpt: "FastGPT", opencode: "OpenCode", }; -const typeFromLabel: Record = { +const typeFromBuildMethod: Record< + Exclude, + ApiAssistantType +> = { 提示词: "prompt", 工作流: "workflow", - Dify: "dify", - FastGPT: "fastgpt", OpenCode: "opencode", }; // 后端 type → 编辑器视图(工作流暂为占位页) const typeToView = { prompt: "create", - dify: "create-dify", - fastgpt: "create-fastgpt", + dify: "create-agent-platform", + fastgpt: "create-agent-platform", opencode: "create-opencode", workflow: "workflow", } as const; @@ -186,20 +181,10 @@ function blankPromptForm(name: string): AssistantForm { }; } -function blankFastGptForm(name: string): FastGptForm { - return { - name, - agent: "", - asr: "", - voice: "", - enableInterrupt: true, - turnConfig: defaultTurnConfig(), - }; -} - -function blankDifyForm(name: string): DifyForm { +function blankAgentPlatformForm(name: string): AgentPlatformForm { return { name, + platform: "dify", agent: "", asr: "", voice: "", @@ -233,11 +218,11 @@ function formatTimestamp(iso?: string | null): string { } type AssistantTypeOption = { - type: AssistantType; + type: BuildMethod; label: string; description: string; icon: React.ReactNode; - /** 提示词、工作流、Dify、FastGPT 已落地;OpenCode 暂时显示即将上线 */ + /** 提示词、工作流、智能体平台已落地;OpenCode 暂时显示即将上线 */ available: boolean; }; @@ -257,19 +242,13 @@ const assistantTypeOptions: AssistantTypeOption[] = [ available: true, }, { - type: "Dify", - label: "使用 Dify 构建", - description: "对接 Dify 应用,复用其编排能力与知识库配置。", + type: "智能体平台", + label: "从智能体平台创建", + description: + "接入 Dify、FastGPT 等智能体平台,复用平台中的提示词、知识库和工作流配置。", icon: , available: true, }, - { - type: "FastGPT", - label: "使用 FastGPT 构建", - description: "对接 FastGPT 应用,复用其知识库问答与工作流能力。", - icon: , - available: true, - }, { type: "OpenCode", label: "使用 OpenCode 构建", @@ -301,10 +280,10 @@ export function AssistantPage(props: AssistantPageProps) { const editingId = props.mode === "edit" ? props.assistantId : null; const [form, setForm] = useState(() => blankPromptForm("")); - const [fastGptForm, setFastGptForm] = useState(() => - blankFastGptForm(""), + const [agentPlatformForm, setAgentPlatformForm] = + useState(() => + blankAgentPlatformForm(""), ); - const [difyForm, setDifyForm] = useState(() => blankDifyForm("")); const [openCodeForm, setOpenCodeForm] = useState(() => blankOpenCodeForm(""), ); @@ -333,7 +312,9 @@ export function AssistantPage(props: AssistantPageProps) { // choose 步骤的草稿:名称与已选类型,确认后直接建库并进入编辑页 // (工作流占位页也用它展示名称与类型) const [draftName, setDraftName] = useState(""); - const [draftType, setDraftType] = useState(null); + const [draftType, setDraftType] = useState(null); + const [draftAgentPlatform, setDraftAgentPlatform] = + useState(null); // 引导页:创建请求进行中 / 创建失败 const [creating, setCreating] = useState(false); const [createError, setCreateError] = useState(null); @@ -499,17 +480,29 @@ export function AssistantPage(props: AssistantPageProps) { // 引导页确认:直接创建到数据库拿到 id,再进入该助手的编辑页 async function confirmType() { - if (!draftName.trim() || !draftType || creating) { + if ( + !draftName.trim() || + !draftType || + (draftType === "智能体平台" && !draftAgentPlatform) || + creating + ) { return; } setCreating(true); setCreateError(null); try { + let assistantType: ApiAssistantType; + if (draftType === "智能体平台") { + if (!draftAgentPlatform) return; + assistantType = draftAgentPlatform; + } else { + assistantType = typeFromBuildMethod[draftType]; + } const created = await assistantsApi.create( baseUpsert({ name: draftName.trim(), - type: typeFromLabel[draftType], + type: assistantType, }), ); router.push(`/assistants/${created.id}`); @@ -573,13 +566,9 @@ export function AssistantPage(props: AssistantPageProps) { await assistantsApi.update(editingId, payload); if (view === "create") { setSavedSnapshot(JSON.stringify(form)); - } else if (view === "create-dify") { - const next = { ...difyForm }; - setDifyForm(next); - setSavedSnapshot(JSON.stringify(next)); - } else if (view === "create-fastgpt") { - const next = { ...fastGptForm }; - setFastGptForm(next); + } else if (view === "create-agent-platform") { + const next = { ...agentPlatformForm }; + setAgentPlatformForm(next); setSavedSnapshot(JSON.stringify(next)); } else if (view === "create-opencode") { const next = { ...openCodeForm }; @@ -628,61 +617,36 @@ export function AssistantPage(props: AssistantPageProps) { ); } - // ---- Dify ---- - function fillDifyForm(a: Assistant): DifyForm { - const next: DifyForm = { + // ---- 外部智能体平台(Dify / FastGPT)---- + function fillAgentPlatformForm(a: Assistant): AgentPlatformForm { + const next: AgentPlatformForm = { name: a.name, + platform: a.type === "fastgpt" ? "fastgpt" : "dify", agent: a.modelResourceIds.Agent ?? "", asr: a.modelResourceIds.ASR ?? "", voice: a.modelResourceIds.TTS ?? "", enableInterrupt: a.enableInterrupt, turnConfig: normalizeTurnConfig(a.turnConfig), }; - setDifyForm(next); + setAgentPlatformForm(next); return next; } - function handleSaveDify() { + function handleSaveAgentPlatform() { void save( baseUpsert({ - name: difyForm.name.trim(), - type: "dify", - enableInterrupt: difyForm.enableInterrupt, - turnConfig: difyForm.turnConfig, + name: agentPlatformForm.name.trim(), + type: agentPlatformForm.platform, + enableInterrupt: agentPlatformForm.enableInterrupt, + turnConfig: agentPlatformForm.turnConfig, modelResourceIds: { - ...(difyForm.agent ? { Agent: difyForm.agent } : {}), - ...(difyForm.asr ? { ASR: difyForm.asr } : {}), - ...(difyForm.voice ? { TTS: difyForm.voice } : {}), - }, - }), - ); - } - - // ---- FastGPT ---- - function fillFastGptForm(a: Assistant): FastGptForm { - const next: FastGptForm = { - name: a.name, - agent: a.modelResourceIds.Agent ?? "", - asr: a.modelResourceIds.ASR ?? "", - voice: a.modelResourceIds.TTS ?? "", - enableInterrupt: a.enableInterrupt, - turnConfig: normalizeTurnConfig(a.turnConfig), - }; - setFastGptForm(next); - return next; - } - - function handleSaveFastGpt() { - void save( - baseUpsert({ - name: fastGptForm.name.trim(), - type: "fastgpt", - enableInterrupt: fastGptForm.enableInterrupt, - turnConfig: fastGptForm.turnConfig, - modelResourceIds: { - ...(fastGptForm.agent ? { Agent: fastGptForm.agent } : {}), - ...(fastGptForm.asr ? { ASR: fastGptForm.asr } : {}), - ...(fastGptForm.voice ? { TTS: fastGptForm.voice } : {}), + ...(agentPlatformForm.agent + ? { Agent: agentPlatformForm.agent } + : {}), + ...(agentPlatformForm.asr ? { ASR: agentPlatformForm.asr } : {}), + ...(agentPlatformForm.voice + ? { TTS: agentPlatformForm.voice } + : {}), }, }), ); @@ -717,10 +681,11 @@ export function AssistantPage(props: AssistantPageProps) { if (cancelled) return; if (assistant.type === "prompt") { setSavedSnapshot(JSON.stringify(fillPromptForm(assistant))); - } else if (assistant.type === "fastgpt") { - setSavedSnapshot(JSON.stringify(fillFastGptForm(assistant))); - } else if (assistant.type === "dify") { - setSavedSnapshot(JSON.stringify(fillDifyForm(assistant))); + } else if ( + assistant.type === "fastgpt" || + assistant.type === "dify" + ) { + setSavedSnapshot(JSON.stringify(fillAgentPlatformForm(assistant))); } else if (assistant.type === "opencode") { setSavedSnapshot(JSON.stringify(fillOpenCodeForm(assistant))); } else { @@ -845,21 +810,19 @@ export function AssistantPage(props: AssistantPageProps) { const activeFormJson = view === "create" ? JSON.stringify(form) - : view === "create-dify" - ? JSON.stringify(difyForm) - : view === "create-fastgpt" - ? JSON.stringify(fastGptForm) - : view === "create-opencode" - ? JSON.stringify(openCodeForm) - : view === "workflow" - ? JSON.stringify({ - name: workflowName, - graph: workflowGraph, - settings: workflowSettings, - dynamicVariableDefinitions: - effectiveWorkflowDynamicVariableDefinitions, - }) - : null; + : view === "create-agent-platform" + ? JSON.stringify(agentPlatformForm) + : view === "create-opencode" + ? JSON.stringify(openCodeForm) + : view === "workflow" + ? JSON.stringify({ + name: workflowName, + graph: workflowGraph, + settings: workflowSettings, + dynamicVariableDefinitions: + effectiveWorkflowDynamicVariableDefinitions, + }) + : null; const dirty = activeFormJson !== null && savedSnapshot !== null && @@ -936,23 +899,21 @@ export function AssistantPage(props: AssistantPageProps) { })); } - function updateFastGptForm( + function updateAgentPlatformForm( key: K, - value: FastGptForm[K], + value: AgentPlatformForm[K], ) { - setFastGptForm((prev) => ({ + setAgentPlatformForm((prev) => ({ ...prev, [key]: value, })); } - function updateDifyForm( - key: K, - value: DifyForm[K], - ) { - setDifyForm((prev) => ({ + function handleAgentPlatformChange(platform: AgentPlatform) { + setAgentPlatformForm((prev) => ({ ...prev, - [key]: value, + platform, + agent: prev.platform === platform ? prev.agent : "", })); } @@ -1210,7 +1171,7 @@ export function AssistantPage(props: AssistantPageProps) {
构建方式
-
+
{assistantTypeOptions.map((option) => { const selected = draftType === option.type; @@ -1258,6 +1219,40 @@ export function AssistantPage(props: AssistantPageProps) { ); })}
+ + {draftType === "智能体平台" && ( +
+
+ 选择智能体平台 +
+

+ 平台类型用于匹配对应的应用资源和运行方式。 +

+
+ {(["dify", "fastgpt"] as const).map((platform) => { + const selected = draftAgentPlatform === platform; + const label = platform === "dify" ? "Dify" : "FastGPT"; + + return ( + + ); + })} +
+
+ )}
@@ -1276,7 +1271,12 @@ export function AssistantPage(props: AssistantPageProps) { -
- - -
-
- } - title="Dify 应用配置" - description="从「模型资源」中选择 Dify 应用。开场白、知识库、提示词等对话编排请在 Dify 平台配置,本页不重复设置。" - > - updateDifyForm("agent", value)} - options={agentOptions("dify")} - noneLabel="请选择" - /> - - - } - title="语音配置" - description="从「模型资源」中选择语音识别与语音合成。大模型、知识库与开场白由 Dify 应用提供,请前往 Dify 平台配置。" - > - updateDifyForm("asr", value)} - options={credOptions("ASR")} - noneLabel="无" - /> - updateDifyForm("voice", value)} - options={credOptions("TTS")} - noneLabel="无" - /> - - - } - title="交互策略" - description="设置实时视频对话时的交互体验" - > - updateDifyForm("enableInterrupt", checked)} - onConfigChange={(config) => updateDifyForm("turnConfig", config)} - /> - -
- - -
- - ); - } - - if (view === "create-fastgpt") { - return ( -
-
-
- router.push("/assistants")} /> - updateFastGptForm("name", value)} + value={agentPlatformForm.name} + onChange={(value) => updateAgentPlatformForm("name", value)} />
@@ -1453,10 +1363,10 @@ export function AssistantPage(props: AssistantPageProps) { disabled={ saving || !dirty || - !fastGptForm.name.trim() || - !fastGptForm.agent + !agentPlatformForm.name.trim() || + !agentPlatformForm.agent } - onClick={() => void handleSaveFastGpt()} + onClick={() => void handleSaveAgentPlatform()} > {saving ? ( @@ -1471,15 +1381,44 @@ export function AssistantPage(props: AssistantPageProps) {
} - title="FastGPT 应用配置" - description="从「模型资源」中选择 FastGPT 应用。开场白、知识库、提示词等对话编排请在 FastGPT 平台配置,本页不重复设置。" + icon={} + title="智能体平台配置" + description={`选择智能体平台及对应应用。开场白、知识库、提示词等对话编排请在 ${platformLabel} 平台配置,本页不重复设置。`} > +
+
+ 智能体平台 +
+
+ {(["dify", "fastgpt"] as const).map((platform) => { + const selected = agentPlatformForm.platform === platform; + const label = platform === "dify" ? "Dify" : "FastGPT"; + + return ( + + ); + })} +
+
updateFastGptForm("agent", value)} - options={agentOptions("fastgpt")} + label={`${platformLabel} 应用`} + value={agentPlatformForm.agent} + onChange={(value) => updateAgentPlatformForm("agent", value)} + options={agentOptions(agentPlatformForm.platform)} noneLabel="请选择" />
@@ -1487,19 +1426,19 @@ export function AssistantPage(props: AssistantPageProps) { } title="语音配置" - description="从「模型资源」中选择语音识别与语音合成。大模型、知识库与开场白由 FastGPT 应用提供,请前往 FastGPT 平台配置。" + description={`从「模型资源」中选择语音识别与语音合成。大模型、知识库与开场白由 ${platformLabel} 应用提供,请前往 ${platformLabel} 平台配置。`} > updateFastGptForm("asr", value)} + value={agentPlatformForm.asr} + onChange={(value) => updateAgentPlatformForm("asr", value)} options={credOptions("ASR")} noneLabel="无" /> updateFastGptForm("voice", value)} + value={agentPlatformForm.voice} + onChange={(value) => updateAgentPlatformForm("voice", value)} options={credOptions("TTS")} noneLabel="无" /> @@ -1511,19 +1450,19 @@ export function AssistantPage(props: AssistantPageProps) { description="设置实时视频对话时的交互体验" > updateFastGptForm("enableInterrupt", checked)} - onConfigChange={(config) => updateFastGptForm("turnConfig", config)} + enabled={agentPlatformForm.enableInterrupt} + config={agentPlatformForm.turnConfig} + onEnabledChange={(checked) => + updateAgentPlatformForm("enableInterrupt", checked) + } + onConfigChange={(config) => + updateAgentPlatformForm("turnConfig", config) + } />
- +
);