-
-
- 继承全局配置
+
+
+ }
+ title="配置范围"
+ description="默认复用工作流全局的模型、语音、视觉、知识库和工具"
+ >
+
+
+
+ 继承全局配置
+
+
+ {inheritsGlobal
+ ? "全局提示词会与当前节点提示词合并。"
+ : "当前节点使用独立的完整助手配置。"}
+
-
- {inheritsGlobal
- ? "全局提示词会与当前节点提示词合并。"
- : "当前节点使用独立的完整助手配置。"}
-
+
-
-
-
+
+
-
}
- title={inheritsGlobal ? "任务" : "提示词"}
- description={
- inheritsGlobal
- ? "描述当前阶段要完成的目标;角色、能力和通用规则继承工作流全局配置"
- : "描述当前独立助手的角色、能力和回答要求"
- }
- >
-
+
);
}
diff --git a/frontend/src/components/workflow/panels/EdgeSettingsPanel.tsx b/frontend/src/components/workflow/panels/EdgeSettingsPanel.tsx
index 595e2ec..9d16495 100644
--- a/frontend/src/components/workflow/panels/EdgeSettingsPanel.tsx
+++ b/frontend/src/components/workflow/panels/EdgeSettingsPanel.tsx
@@ -22,6 +22,10 @@ import {
import { Textarea } from "@/components/ui/textarea";
import { NodeSelect } from "./controls";
+import {
+ PanelAnchor,
+ PanelAnchorNavigation,
+} from "./PanelAnchorNavigation";
import type { ExpressionRule, WorkflowEdgeData } from "../specs";
export function EdgeSettingsPanel({
@@ -85,8 +89,15 @@ export function EdgeSettingsPanel({
};
return (
-
-
+
+ }
title="路由方式"
description="每个节点最多一条默认路径,也可以配置多条条件路径"
@@ -124,9 +135,11 @@ export function EdgeSettingsPanel({
Agent 不能只有默认路径;请改为条件路径,或删除连接以持续对话。
)}
-
+
+
-
+ }
title="触发条件"
description="配置这条连接被命中的条件"
@@ -271,7 +284,8 @@ export function EdgeSettingsPanel({
当前节点没有其它条件命中时,将沿这条默认路径继续执行。
)}
-
-
+
+
+
);
}
diff --git a/frontend/src/components/workflow/panels/GlobalSettingsPanel.tsx b/frontend/src/components/workflow/panels/GlobalSettingsPanel.tsx
index f4cc419..74fc3f7 100644
--- a/frontend/src/components/workflow/panels/GlobalSettingsPanel.tsx
+++ b/frontend/src/components/workflow/panels/GlobalSettingsPanel.tsx
@@ -15,6 +15,10 @@ import { TurnConfigEditor } from "@/components/turn-config-editor";
import { Textarea } from "@/components/ui/textarea";
import { ModelSelect, NodeSelect, ToolOptionPicker } from "./controls";
+import {
+ PanelAnchor,
+ PanelAnchorNavigation,
+} from "./PanelAnchorNavigation";
import type {
ModelOption,
WorkflowEditorProps,
@@ -35,134 +39,150 @@ export function GlobalSettingsPanel({
knowledgeOptions: ModelOption[];
}) {
return (
-
-
}
- title="全局提示词"
- description="与所有选择继承全局配置的 Agent 节点提示词合并"
- >
-
+
+
}
+ title="知识库配置"
+ description="所有继承全局配置的 Agent 都可以使用该知识库"
+ >
+
+ 知识库选择
+
+ onSettingsChange({ ...settings, knowledgeRetrievalConfig })
+ }
+ />
+
+
+ onSettingsChange({
+ ...settings,
+ knowledgeBaseId: knowledgeBaseId || "",
+ })
+ }
+ noneLabel="无"
+ />
+
+
+ }
+ title="工具"
+ description="所有继承全局配置的 Agent 都可以调用这些工具"
+ >
+ onSettingsChange({ ...settings, toolIds })}
+ />
+
+
+
+
+ }
+ title="交互策略"
+ description="设置实时视频对话时的交互体验"
+ >
+
+ onSettingsChange({ ...settings, allowInterrupt })
+ }
+ onConfigChange={(turnConfig) =>
+ onSettingsChange({ ...settings, turnConfig })
+ }
+ />
+
+
+
);
}
diff --git a/frontend/src/components/workflow/panels/MessageNodePanel.tsx b/frontend/src/components/workflow/panels/MessageNodePanel.tsx
index 1a9c5e7..37deef7 100644
--- a/frontend/src/components/workflow/panels/MessageNodePanel.tsx
+++ b/frontend/src/components/workflow/panels/MessageNodePanel.tsx
@@ -18,6 +18,7 @@ import {
type MessageCompletionPolicy,
type WorkflowNodeData,
} from "../specs";
+import { PanelAnchor } from "./PanelAnchorNavigation";
const COMPLETION_OPTIONS: Array<{
value: MessageCompletionPolicy;
@@ -65,7 +66,8 @@ export function MessageNodePanel({
return (
<>
-
+ }
title="固定播报"
description="配置进入 Message 节点后播放的固定话术"
@@ -91,9 +93,11 @@ export function MessageNodePanel({
请输入播报内容。
)}
-
+
+
-
+ }
title="继续方式"
description="控制 Message 节点何时进入下一节点"
@@ -169,7 +173,8 @@ export function MessageNodePanel({
)}
-
+
+
>
);
}
diff --git a/frontend/src/components/workflow/panels/NodeSettingsPanel.tsx b/frontend/src/components/workflow/panels/NodeSettingsPanel.tsx
index 20daea5..63c9f41 100644
--- a/frontend/src/components/workflow/panels/NodeSettingsPanel.tsx
+++ b/frontend/src/components/workflow/panels/NodeSettingsPanel.tsx
@@ -13,6 +13,11 @@ import { ActionNodePanel } from "./ActionNodePanel";
import { AgentNodePanel } from "./AgentNodePanel";
import { MessageNodePanel } from "./MessageNodePanel";
import { NodeSelect, ToolOptionPicker } from "./controls";
+import {
+ PanelAnchor,
+ PanelAnchorNavigation,
+ type PanelAnchorSection,
+} from "./PanelAnchorNavigation";
import type { RuntimeNodeSpec, WorkflowNodeData } from "../specs";
import type { ModelOption, WorkflowSettings } from "../types";
@@ -78,20 +83,39 @@ export function NodeSettingsPanel({
if (panel) {
if (spec.type !== "agent") {
+ const sections: PanelAnchorSection[] =
+ spec.type === "message"
+ ? [
+ { id: "speech", label: "固定播报" },
+ { id: "completion", label: "继续方式" },
+ ]
+ : spec.type === "action"
+ ? [{ id: "execution", label: "工具执行" }]
+ : spec.type === "handoff"
+ ? [{ id: "handoff", label: "转交配置" }]
+ : spec.type === "end"
+ ? [{ id: "end", label: "结束配置" }]
+ : [];
+
return (
-
{spec.type === "action" && (
-
+
+
+
)}
{spec.type === "message" && (
@@ -316,11 +342,12 @@ function WorkflowNodePanelForm({
)}
{spec.type === "handoff" && (
-
}
- title="转交配置"
- description="发送转交事件并继续执行工作流"
- >
+
+ }
+ title="转交配置"
+ description="发送转交事件并继续执行工作流"
+ >
-
+
+
)}
{spec.type === "end" && (
-
}
- title="结束配置"
- description="结束工作流,并可在结束前播放一段固定回复"
- >
+
+ }
+ title="结束配置"
+ description="结束工作流,并可在结束前播放一段固定回复"
+ >
-
+
+
)}
);
diff --git a/frontend/src/components/workflow/panels/PanelAnchorNavigation.tsx b/frontend/src/components/workflow/panels/PanelAnchorNavigation.tsx
new file mode 100644
index 0000000..0294dd0
--- /dev/null
+++ b/frontend/src/components/workflow/panels/PanelAnchorNavigation.tsx
@@ -0,0 +1,182 @@
+"use client";
+
+import type { ReactNode } from "react";
+import { useEffect, useRef, useState } from "react";
+
+export type PanelAnchorSection = {
+ id: string;
+ label: string;
+};
+
+export function PanelAnchorNavigation({
+ ariaLabel,
+ sections,
+ children,
+}: {
+ ariaLabel: string;
+ sections: readonly PanelAnchorSection[];
+ children: ReactNode;
+}) {
+ const scrollContainerRef = useRef