feat: 优化工作流字段化参数配置

- 开始节点固定 user_input 并区分系统入口与自定义参数

- LLM 与知识库节点切换为字段值加上游引用配置

- 单节点调试改为字段预览与上游引用输入模式
This commit is contained in:
2026-04-12 20:31:02 +08:00
parent 47655a728b
commit 8cfe5400fe
24 changed files with 2785 additions and 792 deletions

View File

@@ -37,6 +37,11 @@
import {onDestroy, onMount} from 'svelte';
import {isInEditableElement} from '#components/utils/isInEditableElement';
import {getAvailableNodes, type NodePaletteItem} from './utils/nodePalette';
import {
buildSequentialFieldBindingPatches,
ensureStartNodeParameters,
START_NODE_TYPE,
} from '../utils/workflowNodeFields';
const { onInit }: { onInit: any; [key: string]: any } = $props();
const svelteFlow = useSvelteFlow();
@@ -142,6 +147,13 @@
}
} as Node;
if (newNode.type === START_NODE_TYPE) {
newNode.data = {
...(newNode.data || {}),
parameters: ensureStartNodeParameters((newNode.data?.parameters as Array<any>) || [])
};
}
if (sourceNode) {
if (connection?.sourceHandle === 'loop_handle') {
newNode.parentId = sourceNode.id;
@@ -173,6 +185,8 @@
});
store.addEdge(edge as Edge);
}
applyAutoBindingsForNode(newNode.id);
}
function closeNodePicker() {
@@ -367,6 +381,47 @@
const { getNodesFromSource } = useGetNodesFromSource();
const { getNodeRelativePosition } = useGetNodeRelativePosition();
const { ensureParentInNodesBefore } = useEnsureParentInNodesBefore();
function collectAffectedNodeIds(rootNodeIds: string[], edges: Edge[] = store.getEdges()) {
const affectedNodeIds = new Set<string>();
const visit = (nodeId: string) => {
if (!nodeId || affectedNodeIds.has(nodeId)) {
return;
}
affectedNodeIds.add(nodeId);
edges
.filter((edge) => edge.source === nodeId && edge.sourceHandle !== 'loop_handle')
.forEach((edge) => {
if (edge.target) {
visit(edge.target);
}
});
};
rootNodeIds.forEach(visit);
return Array.from(affectedNodeIds);
}
function reconcileBindingsForNodes(
nodeIds: string[],
options?: {
nodes?: Node[];
edges?: Edge[];
}
) {
const uniqueNodeIds = Array.from(new Set(nodeIds.filter((nodeId) => asString(nodeId).trim())));
if (uniqueNodeIds.length === 0) {
return;
}
queueMicrotask(() => {
const nodes = options?.nodes || store.getNodes();
const edges = options?.edges || store.getEdges();
const patches = buildSequentialFieldBindingPatches(uniqueNodeIds, nodes, edges);
patches.forEach(({ nodeId, patch }) => {
store.updateNodeData(nodeId, patch);
});
});
}
const onconnectend = (event: any, state: any) => {
if (!state.isValid) {
if (state.toNode) {
@@ -449,7 +504,11 @@
const { getEdgesByTarget } = useGetEdgesByTarget();
const onDelete = (params: any) => {
const deleteEdges = params.edges as Edge[];
const affectedRootNodeIds = new Set<string>();
deleteEdges.forEach((edge) => {
if (edge.target) {
affectedRootNodeIds.add(edge.target);
}
if (edge.id === currentEdge?.id) {
currentEdge = null;
showEdgePanel = false;
@@ -513,6 +572,11 @@
}
}
});
if (affectedRootNodeIds.size > 0) {
queueMicrotask(() => {
reconcileBindingsForNodes(collectAffectedNodeIds(Array.from(affectedRootNodeIds)));
});
}
};
const { deleteEdge } = useDeleteEdge();
@@ -525,9 +589,41 @@
const onconnect = (event: any) => {
// console.log('onconnect: ', event);
const targetNodeId = asString(event?.target).trim();
if (!targetNodeId) {
return;
}
const sourceNodeId = asString(event?.source).trim();
const projectedEdges = [...store.getEdges()];
const hasSameEdge = projectedEdges.some((edge) =>
edge.source === sourceNodeId
&& edge.target === targetNodeId
&& (edge.sourceHandle || '') === asString(event?.sourceHandle).trim()
&& (edge.targetHandle || '') === asString(event?.targetHandle).trim()
);
if (!hasSameEdge && sourceNodeId) {
projectedEdges.push({
id: asString(event?.id).trim() || `edge_${genShortId()}`,
source: sourceNodeId,
target: targetNodeId,
sourceHandle: asString(event?.sourceHandle).trim() || undefined,
targetHandle: asString(event?.targetHandle).trim() || undefined,
} as Edge);
}
reconcileBindingsForNodes(
collectAffectedNodeIds([targetNodeId], projectedEdges),
{
edges: projectedEdges
}
);
};
function applyAutoBindingsForNode(nodeId: string) {
reconcileBindingsForNodes([nodeId]);
}
const { copyHandler, pasteHandler } = useCopyPasteHandler();
const handleKeyDown = (e: KeyboardEvent) => {