diff --git a/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx b/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx index 5bd94265a..80d449e5d 100644 --- a/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx +++ b/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx @@ -26,6 +26,7 @@ import { Video, } from "lucide-react"; import { + AGENT_WORKFLOW_MAX_OPTION_DEPTH, AGENT_WORKFLOW_MAX_TREE_DEPTH, countAgentWorkflowOptions, countAgentWorkflowOptionTree, @@ -104,10 +105,20 @@ const itemVariants = { visible: { opacity: 1, y: 0 } }; -const WORKFLOW_LEVEL_LABELS = ["一级模块", "二级模块", "三级模块"]; -const WORKFLOW_OPTION_LEVEL_LABELS = ["一级卡片", "二级卡片", "三级卡片"]; +const CHINESE_LEVEL_NUMERALS = ["一", "二", "三", "四", "五", "六", "七", "八"]; +const WORKFLOW_LEVEL_LABELS = CHINESE_LEVEL_NUMERALS.map((item) => `${item}级模块`); +const WORKFLOW_OPTION_LEVEL_LABELS = CHINESE_LEVEL_NUMERALS.map((item) => `${item}级卡片`); const PRESET_LIBRARY_LEVEL_LABELS = ["一级分类", "二级分类", "三级分类"]; +function getWorkflowLevelLabel(depth: number, kind: "模块" | "卡片") { + const labels = + kind === "模块" ? WORKFLOW_LEVEL_LABELS : WORKFLOW_OPTION_LEVEL_LABELS; + return ( + labels[Math.max(0, Math.min(depth - 1, labels.length - 1))] || + `第 ${depth} 级${kind}` + ); +} + function normalizeConfigOrdering(config: AgentWorkflowUiConfig): AgentWorkflowUiConfig { return { ...config, @@ -168,7 +179,7 @@ function createWorkflowStepDraft( stepIndex: number, existingStepKeys: string[] ): AgentWorkflowStepUiConfig { - const levelLabel = WORKFLOW_LEVEL_LABELS[Math.max(0, Math.min(depth - 1, 2))] || "模块"; + const levelLabel = getWorkflowLevelLabel(depth, "模块"); const stepKey = ensureUniqueWorkflowKey(`step_${depth}_${stepIndex + 1}`, existingStepKeys); return { key: stepKey, @@ -880,7 +891,7 @@ export function AgentWorkflowSettingsClient({ const parentDepth = flattenAgentWorkflowOptionTree(step.options || []).find( ({ option }) => option.key === parentOptionKey )?.depth; - if (!parentOption || !parentDepth || parentDepth >= 3) { + if (!parentOption || !parentDepth || parentDepth >= AGENT_WORKFLOW_MAX_OPTION_DEPTH) { return step; } @@ -1196,13 +1207,11 @@ export function AgentWorkflowSettingsClient({ ): ReactNode => { const refKey = `${step.key}:${option.key}`; const isUploading = uploadingKey === refKey; - const levelLabel = - WORKFLOW_OPTION_LEVEL_LABELS[Math.max(0, Math.min(depth - 1, WORKFLOW_OPTION_LEVEL_LABELS.length - 1))] || - `第 ${depth} 级卡片`; + const levelLabel = getWorkflowLevelLabel(depth, "卡片"); const sortedChildren = [...(option.children || [])].sort( (left, right) => left.sortOrder - right.sortOrder ); - const canAddChild = depth < 3; + const canAddChild = depth < AGENT_WORKFLOW_MAX_OPTION_DEPTH; return (
1 && "pl-4 sm:pl-6")}> @@ -1334,7 +1343,7 @@ export function AgentWorkflowSettingsClient({ 新增子卡片 ) : ( - 已达三级 + {`已达 ${AGENT_WORKFLOW_MAX_OPTION_DEPTH} 级`} )}
@@ -1394,9 +1403,7 @@ export function AgentWorkflowSettingsClient({ indexPath: number[] ) => { const stepLabel = indexPath.join("."); - const levelLabel = - WORKFLOW_LEVEL_LABELS[Math.max(0, Math.min(depth - 1, WORKFLOW_LEVEL_LABELS.length - 1))] || - `第 ${depth} 级模块`; + const levelLabel = getWorkflowLevelLabel(depth, "模块"); const rootOptions = [...(step.options || [])].sort((left, right) => left.sortOrder - right.sortOrder); const optionCardCount = countAgentWorkflowOptionTree(step.options || []); diff --git a/components/agents/AgentWorkflowPanelDarkV2.tsx b/components/agents/AgentWorkflowPanelDarkV2.tsx index 7d7d15d25..48b1b855d 100644 --- a/components/agents/AgentWorkflowPanelDarkV2.tsx +++ b/components/agents/AgentWorkflowPanelDarkV2.tsx @@ -111,6 +111,50 @@ function getWorkflowStepSelectionSummary(params: { return selectedOptions.map((option) => option.buttonName).join(" / "); } +function getWorkflowStepOptionLevels(params: { + step: AgentWorkflowUiConfig["steps"][number]; + selectionValue?: string; +}) { + const levels: Array<{ + depth: number; + options: AgentWorkflowUiConfig["steps"][number]["options"]; + selectedKey: string; + selectedOption: AgentWorkflowUiConfig["steps"][number]["options"][number] | null; + }> = []; + const selectedPath = getAgentWorkflowSelectedOptionPath({ + step: params.step, + selectionValue: params.selectionValue, + }); + + let depth = 1; + let currentOptions = getEnabledAgentWorkflowOptionTree(params.step.options || []); + + while (currentOptions.length > 0) { + const selectedKey = selectedPath[depth - 1]?.key || ""; + const selectedOption = + currentOptions.find((option) => option.key === selectedKey) || null; + + levels.push({ + depth, + options: currentOptions, + selectedKey, + selectedOption, + }); + + const nextOptions = getEnabledAgentWorkflowOptionTree( + selectedOption?.children || [] + ); + if (!selectedOption || nextOptions.length === 0) { + break; + } + + currentOptions = nextOptions; + depth += 1; + } + + return levels; +} + function StepOptionCard({ option, step, @@ -346,6 +390,7 @@ export function AgentWorkflowPanelDarkV2({ return Object.fromEntries(entries) as Record; }, [resolvedConfig.steps, selections]); const [activeEmbeddedStepKey, setActiveEmbeddedStepKey] = useState(""); + const [activeEmbeddedOptionDepth, setActiveEmbeddedOptionDepth] = useState(1); const [pendingAutoAdvanceStepKey, setPendingAutoAdvanceStepKey] = useState(null); const activeEmbeddedStepIndex = Math.max( flattenedResolvedSteps.findIndex(({ step }) => step.key === activeEmbeddedStepKey), @@ -353,6 +398,21 @@ export function AgentWorkflowPanelDarkV2({ ); const activeEmbeddedStepEntry = flattenedResolvedSteps[activeEmbeddedStepIndex] || flattenedResolvedSteps[0] || null; + const activeEmbeddedOptionLevels = useMemo( + () => + activeEmbeddedStepEntry + ? getWorkflowStepOptionLevels({ + step: activeEmbeddedStepEntry.step, + selectionValue: selections[activeEmbeddedStepEntry.step.key], + }) + : [], + [activeEmbeddedStepEntry, selections] + ); + const activeEmbeddedOptionLevel = + activeEmbeddedOptionLevels.find((level) => level.depth === activeEmbeddedOptionDepth) || + activeEmbeddedOptionLevels[activeEmbeddedOptionLevels.length - 1] || + activeEmbeddedOptionLevels[0] || + null; useEffect(() => { if (!embedded) { @@ -376,6 +436,33 @@ export function AgentWorkflowPanelDarkV2({ setActiveEmbeddedStepKey(flattenedResolvedSteps[0]?.step.key || ""); }, [activeEmbeddedStepKey, embedded, flattenedResolvedSteps]); + useEffect(() => { + if (!embedded) { + return; + } + + if (!activeEmbeddedStepEntry) { + if (activeEmbeddedOptionDepth !== 1) { + setActiveEmbeddedOptionDepth(1); + } + return; + } + + const firstIncompleteDepth = + activeEmbeddedOptionLevels.find((level) => !level.selectedKey)?.depth || + activeEmbeddedOptionLevels[activeEmbeddedOptionLevels.length - 1]?.depth || + 1; + + setActiveEmbeddedOptionDepth((current) => { + const maxDepth = + activeEmbeddedOptionLevels[activeEmbeddedOptionLevels.length - 1]?.depth || 1; + if (current < 1 || current > maxDepth) { + return firstIncompleteDepth; + } + return current; + }); + }, [activeEmbeddedOptionDepth, activeEmbeddedOptionLevels, activeEmbeddedStepEntry, embedded]); + useEffect(() => { if (!embedded || !activeEmbeddedStepEntry) { return; @@ -405,6 +492,7 @@ export function AgentWorkflowPanelDarkV2({ if (nextStep && nextStep.step.key !== activeEmbeddedStepKey) { setActiveEmbeddedStepKey(nextStep.step.key); + setActiveEmbeddedOptionDepth(1); } setPendingAutoAdvanceStepKey(null); @@ -611,12 +699,141 @@ export function AgentWorkflowPanelDarkV2({ })} + + {activeEmbeddedOptionLevels.length > 0 ? ( +
+
+
+
子节点流程
+
+ 当前步骤的子节点会在这里逐级展开,减少单屏内容堆积。 +
+
+
+ 共 {activeEmbeddedOptionLevels.length} 级 +
+
+
+ {activeEmbeddedOptionLevels.map((level, levelIndex) => { + const isActive = level.depth === activeEmbeddedOptionDepth; + const summaryText = + level.selectedOption?.buttonName || "待选择"; + return ( + + + {levelIndex < activeEmbeddedOptionLevels.length - 1 ? ( +
+ ) : null} + + ); + })} +
+
+ ) : null}
- {renderOptionLevels( - activeEmbeddedStepEntry.step, - getEnabledAgentWorkflowOptionTree(activeEmbeddedStepEntry.step.options || []) - )} + {activeEmbeddedOptionLevel ? ( +
+
+ + {activeEmbeddedOptionLevel.depth === 1 + ? "主卡片" + : `${activeEmbeddedOptionLevel.depth}级子卡片`} + + + {activeEmbeddedOptionLevel.depth === 1 + ? "先选择当前步骤的主卡片" + : "当前层级只展示这一层的子节点卡片,选完再进入下一层"} + +
+ +
+ {activeEmbeddedOptionLevel.options.map((option, optionIndex) => { + const currentSelectedKey = activeEmbeddedOptionLevel.selectedKey; + const nextChildren = getEnabledAgentWorkflowOptionTree( + option.children || [] + ); + + return ( + { + const selectedPathKeys = activeEmbeddedOptionLevels + .slice(0, activeEmbeddedOptionLevel.depth - 1) + .map((level) => level.selectedKey) + .filter(Boolean); + const nextKeys = + currentSelectedKey === option.key + ? selectedPathKeys + : [...selectedPathKeys, option.key]; + + setPendingAutoAdvanceStepKey(activeEmbeddedStepEntry.step.key); + onSelectionsChange({ + ...selections, + [activeEmbeddedStepEntry.step.key]: + nextKeys.length > 0 + ? serializeAgentWorkflowSelectionPath(nextKeys) + : undefined, + }); + + if (currentSelectedKey !== option.key && nextChildren.length > 0) { + setActiveEmbeddedOptionDepth( + activeEmbeddedOptionLevel.depth + 1 + ); + } else { + setActiveEmbeddedOptionDepth( + activeEmbeddedOptionLevel.depth + ); + } + }} + index={optionIndex} + /> + ); + })} +
+
+ ) : null} ) : null ) : ( @@ -638,7 +855,7 @@ export function AgentWorkflowPanelDarkV2({ {step.title} {depth > 1 ? ( - {depth === 2 ? "二级模块" : "三级模块"} + {`${depth}级模块`} ) : null} diff --git a/lib/agents/workflow-ui-config.ts b/lib/agents/workflow-ui-config.ts index 5300da8a5..4294f0ef3 100644 --- a/lib/agents/workflow-ui-config.ts +++ b/lib/agents/workflow-ui-config.ts @@ -6,8 +6,8 @@ import type { } from "@/types/agent"; export const AGENT_WORKFLOW_UI_CONFIG_KEY = "agent_workflow_ui_config"; -export const AGENT_WORKFLOW_MAX_TREE_DEPTH = 3; -export const AGENT_WORKFLOW_MAX_OPTION_DEPTH = 3; +export const AGENT_WORKFLOW_MAX_TREE_DEPTH = 8; +export const AGENT_WORKFLOW_MAX_OPTION_DEPTH = 8; export interface FlattenedAgentWorkflowStep { step: AgentWorkflowStepUiConfig;