Skip to content

Commit 7b9fae5

Browse files
authored
fix: Set up a complete knowledge base workflow in the loop body, debug prompts that the knowledge base write node cannot be used as the end node (#4476)
1 parent cc36079 commit 7b9fae5

File tree

2 files changed

+100
-9
lines changed

2 files changed

+100
-9
lines changed

ui/src/workflow/common/validate.ts

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const end_nodes_dict = {
4545
[WorkflowMode.Application]: end_nodes,
4646
[WorkflowMode.Knowledge]: [WorkflowType.KnowledgeWriteNode],
4747
[WorkflowMode.ApplicationLoop]: loop_end_nodes,
48-
[WorkflowMode.KnowledgeLoop]: loop_end_nodes,
48+
[WorkflowMode.KnowledgeLoop]: [...loop_end_nodes, WorkflowType.KnowledgeWriteNode],
4949
}
5050

5151
export class WorkFlowInstance {
@@ -218,9 +218,11 @@ export class WorkFlowInstance {
218218

219219
export class KnowledgeWorkFlowInstance extends WorkFlowInstance {
220220
is_valid_start_node() {
221-
const start_node_list = this.nodes.filter(
222-
(item) => item.properties.kind === WorkflowKind.DataSource,
223-
)
221+
const start_node_list =
222+
this.workflowModel == WorkflowMode.Knowledge
223+
? this.nodes.filter((item) => item.properties.kind === WorkflowKind.DataSource)
224+
: this.nodes.filter((item) => item.type === WorkflowType.LoopStartNode)
225+
224226
if (start_node_list.length == 0) {
225227
throw t('workflow.validate.startNodeRequired')
226228
}
@@ -239,9 +241,7 @@ export class KnowledgeWorkFlowInstance extends WorkFlowInstance {
239241

240242
is_valid_work_flow() {
241243
this.workFlowNodes = []
242-
const start_node_list = this.nodes.filter(
243-
(item) => item.properties.kind === WorkflowKind.DataSource,
244-
)
244+
const start_node_list = this.get_start_nodes()
245245
start_node_list.forEach((n) => {
246246
this._is_valid_work_flow(n)
247247
})
@@ -250,10 +250,12 @@ export class KnowledgeWorkFlowInstance extends WorkFlowInstance {
250250
.filter(
251251
(node: any) =>
252252
node.id !== WorkflowType.KnowledgeBase &&
253+
node.type !== WorkflowType.LoopStartNode &&
253254
node.properties.kind !== WorkflowKind.DataSource,
254255
)
255256
.filter((node) => !this.workFlowNodes.includes(node))
256257
if (notInWorkFlowNodes.length > 0) {
258+
console.log('ss')
257259
throw `${t('workflow.validate.notInWorkFlowNode')}:${notInWorkFlowNodes.map((node) => node.properties.stepName).join(',')}`
258260
}
259261
this.workFlowNodes = []
@@ -263,6 +265,7 @@ export class KnowledgeWorkFlowInstance extends WorkFlowInstance {
263265
for (const node of this.nodes) {
264266
if (
265267
node.type !== WorkflowType.KnowledgeBase &&
268+
node.type !== WorkflowType.LoopStartNode &&
266269
node.properties.kind !== WorkflowKind.DataSource
267270
) {
268271
if (!this.edges.some((edge) => edge.targetNodeId === node.id)) {
@@ -271,4 +274,89 @@ export class KnowledgeWorkFlowInstance extends WorkFlowInstance {
271274
}
272275
}
273276
}
277+
get_start_nodes() {
278+
if (this.workflowModel == WorkflowMode.Knowledge) {
279+
return this.nodes.filter((item) => item.properties.kind === WorkflowKind.DataSource)
280+
} else {
281+
return this.nodes.filter((item) => item.type === WorkflowType.LoopStartNode)
282+
}
283+
}
284+
get_end_nodes() {
285+
const start_node_list = this.get_start_nodes()
286+
return start_node_list.flatMap((n) => {
287+
return this._get_end_nodes(n, [])
288+
})
289+
}
290+
_get_end_nodes(startNode: any, value: Array<any>) {
291+
const next = this.get_next_nodes(startNode)
292+
if (next.length == 0) {
293+
value.push(startNode)
294+
} else {
295+
next.forEach((n) => {
296+
this._get_end_nodes(n, value)
297+
})
298+
}
299+
return value
300+
}
301+
302+
/**
303+
* 获取流程下一个节点列表
304+
* @param node 节点
305+
* @returns 节点列表
306+
*/
307+
get_next_nodes(node: any) {
308+
const edge_list = this.edges.filter((edge) => edge.sourceNodeId == node.id)
309+
const node_list = edge_list
310+
.map((edge) => this.nodes.filter((node) => node.id == edge.targetNodeId))
311+
.reduce((x, y) => [...x, ...y], [])
312+
313+
return node_list
314+
}
315+
316+
/**
317+
* 校验节点
318+
* @param node 节点
319+
*/
320+
is_valid_node(node: any) {
321+
if (node.properties.status && node.properties.status === 500) {
322+
throw `${node.properties.stepName} ${t('workflow.validate.nodeUnavailable')}`
323+
}
324+
if (node.type === WorkflowType.Condition) {
325+
const branch_list = node.properties.node_data.branch
326+
for (const branch of branch_list) {
327+
const source_anchor_id = `${node.id}_${branch.id}_right`
328+
const edge_list = this.edges.filter((edge) => edge.sourceAnchorId == source_anchor_id)
329+
if (edge_list.length == 0) {
330+
throw `${node.properties.stepName} ${t('workflow.validate.needConnect1')}${branch.type}${t('workflow.validate.needConnect2')}`
331+
}
332+
}
333+
} else {
334+
const edge_list = this.edges.filter((edge) => edge.sourceNodeId == node.id)
335+
const end = end_nodes_dict[this.workflowModel]
336+
if (this.workflowModel == WorkflowMode.KnowledgeLoop) {
337+
if (edge_list.length == 0 && !end.includes(node.type)) {
338+
throw `${node.properties.stepName} ${t('workflow.validate.cannotEndNode')}`
339+
}
340+
return
341+
}
342+
if (edge_list.length == 0 && !end.includes(node.type)) {
343+
if (node.type == WorkflowType.LoopNode) {
344+
if (node.properties.node_data.loop_body) {
345+
const end_nodes = new KnowledgeWorkFlowInstance(
346+
node.properties.node_data.loop_body,
347+
WorkflowMode.KnowledgeLoop,
348+
).get_end_nodes()
349+
if (!end_nodes.every((n) => end.includes(n.type))) {
350+
throw `${node.properties.stepName} ${t('workflow.validate.cannotEndNode')}`
351+
}
352+
}
353+
} else {
354+
throw `${node.properties.stepName} ${t('workflow.validate.cannotEndNode')}`
355+
}
356+
}
357+
}
358+
if (node.properties.status && node.properties.status !== 200) {
359+
throw `${node.properties.stepName} ${t('workflow.validate.nodeUnavailable')}`
360+
}
361+
}
274362
}

ui/src/workflow/nodes/loop-body-node/index.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Dagre from '@/workflow/plugins/dagre'
1212
import { initDefaultShortcut } from '@/workflow/common/shortcut'
1313
import LoopBodyContainer from '@/workflow/nodes/loop-body-node/LoopBodyContainer.vue'
1414
import { WorkflowMode } from '@/enums/application'
15-
import { WorkFlowInstance } from '@/workflow/common/validate'
15+
import { WorkFlowInstance, KnowledgeWorkFlowInstance } from '@/workflow/common/validate'
1616
import { t } from '@/locales'
1717
import { disconnectByFlow } from '@/workflow/common/teleport'
1818
const loop_workflow_mode = inject('loopWorkflowMode') || WorkflowMode.ApplicationLoop
@@ -21,7 +21,10 @@ const props = defineProps<{ nodeModel: any }>()
2121
const containerRef = ref()
2222
const LoopBodyContainerRef = ref<InstanceType<typeof LoopBodyContainer>>()
2323
const validate = () => {
24-
const workflow = new WorkFlowInstance(lf.value.getGraphData(), WorkflowMode.ApplicationLoop)
24+
const workflow =
25+
loop_workflow_mode == WorkflowMode.ApplicationLoop
26+
? new WorkFlowInstance(lf.value.getGraphData(), WorkflowMode.ApplicationLoop)
27+
: new KnowledgeWorkFlowInstance(lf.value.getGraphData(), WorkflowMode.KnowledgeLoop)
2528
return Promise.all(lf.value.graphModel.nodes.map((element: any) => element?.validate?.()))
2629
.then(() => {
2730
const loop_node_id = props.nodeModel.properties.loop_node_id

0 commit comments

Comments
 (0)