@@ -42,14 +42,15 @@ import type { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edg
4242import type { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type' ;
4343import { addLog } from '../../../common/system/log' ;
4444import { surrenderProcess } from '../../../common/system/tools' ;
45- import type { DispatchFlowResponse } from './type' ;
45+ import type { DispatchFlowResponse , WorkflowDebugResponse } from './type' ;
4646import { removeSystemVariable , rewriteRuntimeWorkFlow } from './utils' ;
4747import { getHandleId } from '@fastgpt/global/core/workflow/utils' ;
4848import { callbackMap } from './constants' ;
4949
5050type Props = Omit < ChatDispatchProps , 'workflowDispatchDeep' > & {
5151 runtimeNodes : RuntimeNodeItemType [ ] ;
5252 runtimeEdges : RuntimeEdgeItemType [ ] ;
53+ defaultSkipNodeQueue ?: WorkflowDebugResponse [ 'skipNodeQueue' ] ;
5354} ;
5455type NodeResponseType = DispatchNodeResultType < {
5556 [ key : string ] : any ;
@@ -100,6 +101,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
100101 // Init some props
101102 return runWorkflow ( {
102103 ...data ,
104+ defaultSkipNodeQueue : data . lastInteractive ?. skipNodeQueue || data . defaultSkipNodeQueue ,
103105 variables : defaultVariables ,
104106 workflowDispatchDeep : 0
105107 } ) . finally ( ( ) => {
@@ -112,12 +114,14 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
112114type RunWorkflowProps = ChatDispatchProps & {
113115 runtimeNodes : RuntimeNodeItemType [ ] ;
114116 runtimeEdges : RuntimeEdgeItemType [ ] ;
117+ defaultSkipNodeQueue ?: WorkflowDebugResponse [ 'skipNodeQueue' ] ;
115118} ;
116119export const runWorkflow = async ( data : RunWorkflowProps ) : Promise < DispatchFlowResponse > => {
117120 let {
118121 res,
119122 runtimeNodes = [ ] ,
120123 runtimeEdges = [ ] ,
124+ defaultSkipNodeQueue,
121125 histories = [ ] ,
122126 variables = { } ,
123127 externalProvider,
@@ -135,9 +139,10 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
135139 flowResponses : [ ] ,
136140 flowUsages : [ ] ,
137141 debugResponse : {
138- finishedNodes : [ ] ,
139- finishedEdges : [ ] ,
140- nextStepRunNodes : [ ]
142+ memoryEdges : [ ] ,
143+ entryNodeIds : [ ] ,
144+ nodeResponses : { } ,
145+ skipNodeQueue : [ ]
141146 } ,
142147 [ DispatchNodeResponseKeyEnum . runTimes ] : 1 ,
143148 [ DispatchNodeResponseKeyEnum . assistantResponses ] : [ ] ,
@@ -151,6 +156,8 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
151156
152157 await rewriteRuntimeWorkFlow ( { nodes : runtimeNodes , edges : runtimeEdges , lang : data . lang } ) ;
153158
159+ const isDebugMode = data . mode === 'debug' ;
160+
154161 /*
155162 工作流队列控制
156163 特点:
@@ -176,7 +183,6 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
176183 chatAssistantResponse : AIChatItemValueItemType [ ] = [ ] ; // The value will be returned to the user
177184 chatNodeUsages : ChatNodeUsageType [ ] = [ ] ;
178185 toolRunResponse : ToolRunResponseItemType ; // Run with tool mode. Result will response to tool node.
179- debugNextStepRunNodes : RuntimeNodeItemType [ ] = [ ] ; // 记录 Debug 模式下,下一个阶段需要执行的节点。
180186 // 记录交互节点,交互节点需要在工作流完全结束后再进行计算
181187 nodeInteractiveResponse :
182188 | {
@@ -186,22 +192,38 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
186192 | undefined ;
187193 system_memories : Record < string , any > = { } ; // Workflow node memories
188194
195+ // Debug
196+ debugNextStepRunNodes : RuntimeNodeItemType [ ] = [ ] ; // 记录 Debug 模式下,下一个阶段需要执行的节点。
197+ debugNodeResponses : WorkflowDebugResponse [ 'nodeResponses' ] = { } ;
198+
189199 // Queue variables
190200 private activeRunQueue = new Set < string > ( ) ;
191- private skipNodeQueue : { node : RuntimeNodeItemType ; skippedNodeIdList : Set < string > } [ ] = [ ] ;
201+ private skipNodeQueue = new Map <
202+ string ,
203+ { node : RuntimeNodeItemType ; skippedNodeIdList : Set < string > }
204+ > ( ) ;
192205 private runningNodeCount = 0 ;
193206 private maxConcurrency : number ;
194207 private resolve : ( e : WorkflowQueue ) => void ;
195208
196209 constructor ( {
197210 maxConcurrency = 10 ,
211+ defaultSkipNodeQueue,
198212 resolve
199213 } : {
200214 maxConcurrency ?: number ;
215+ defaultSkipNodeQueue ?: WorkflowDebugResponse [ 'skipNodeQueue' ] ;
201216 resolve : ( e : WorkflowQueue ) => void ;
202217 } ) {
203218 this . maxConcurrency = maxConcurrency ;
204219 this . resolve = resolve ;
220+
221+ // Init skip node queue
222+ defaultSkipNodeQueue ?. forEach ( ( { id, skippedNodeIdList } ) => {
223+ const node = this . runtimeNodesMap . get ( id ) ;
224+ if ( ! node ) return ;
225+ this . addSkipNode ( node , new Set ( skippedNodeIdList ) ) ;
226+ } ) ;
205227 }
206228
207229 // Add active node to queue (if already in the queue, it will not be added again)
@@ -217,7 +239,18 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
217239 private processActiveNode ( ) {
218240 // Finish
219241 if ( this . activeRunQueue . size === 0 && this . runningNodeCount === 0 ) {
220- if ( this . skipNodeQueue . length > 0 && ! this . nodeInteractiveResponse ) {
242+ if ( isDebugMode ) {
243+ // 没有下一个激活节点,说明debug 进入了一个“即将结束”状态。可以开始处理 skip 节点
244+ if ( this . debugNextStepRunNodes . length === 0 && this . skipNodeQueue . size > 0 ) {
245+ this . processSkipNodes ( ) ;
246+ } else {
247+ this . resolve ( this ) ;
248+ }
249+ return ;
250+ }
251+
252+ // 如果没有交互响应,则开始处理 skip(交互响应的 skip 需要留给后续处理)
253+ if ( this . skipNodeQueue . size > 0 && ! this . nodeInteractiveResponse ) {
221254 this . processSkipNodes ( ) ;
222255 } else {
223256 this . resolve ( this ) ;
@@ -251,11 +284,19 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
251284 }
252285
253286 private addSkipNode ( node : RuntimeNodeItemType , skippedNodeIdList : Set < string > ) {
254- this . skipNodeQueue . push ( { node, skippedNodeIdList } ) ;
287+ // 保证一个node 只在queue里记录一次
288+ const skipNodeSkippedNodeIdList =
289+ this . skipNodeQueue . get ( node . nodeId ) ?. skippedNodeIdList || new Set < string > ( ) ;
290+
291+ const concatSkippedNodeIdList = new Set ( [ ...skippedNodeIdList , ...skipNodeSkippedNodeIdList ] ) ;
292+
293+ this . skipNodeQueue . set ( node . nodeId , { node, skippedNodeIdList : concatSkippedNodeIdList } ) ;
255294 }
256295 private processSkipNodes ( ) {
257- const skipItem = this . skipNodeQueue . shift ( ) ;
296+ // 取一个 node,并且从队列里删除
297+ const skipItem = this . skipNodeQueue . values ( ) . next ( ) . value ;
258298 if ( skipItem ) {
299+ this . skipNodeQueue . delete ( skipItem . node . nodeId ) ;
259300 this . checkNodeCanRun ( skipItem . node , skipItem . skippedNodeIdList ) . finally ( ( ) => {
260301 this . processActiveNode ( ) ;
261302 } ) ;
@@ -351,7 +392,7 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
351392 runtimeNodes,
352393 runtimeEdges,
353394 params,
354- mode : data . mode === 'debug' ? 'test' : data . mode
395+ mode : isDebugMode ? 'test' : data . mode
355396 } ;
356397
357398 // run module
@@ -620,18 +661,6 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
620661 const nextStepActiveNodes = Array . from ( nextStepActiveNodesMap . values ( ) ) ;
621662 const nextStepSkipNodes = Array . from ( nextStepSkipNodesMap . values ( ) ) ;
622663
623- if ( data . mode === 'debug' ) {
624- this . debugNextStepRunNodes = this . debugNextStepRunNodes . concat (
625- data . lastInteractive
626- ? nextStepActiveNodes
627- : [ ...nextStepActiveNodes , ...nextStepSkipNodes ]
628- ) ;
629- return {
630- nextStepActiveNodes : [ ] ,
631- nextStepSkipNodes : [ ]
632- } ;
633- }
634-
635664 return {
636665 nextStepActiveNodes,
637666 nextStepSkipNodes
@@ -690,8 +719,31 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
690719 return this . nodeRunWithSkip ( node ) ;
691720 }
692721 } ) ( ) ;
722+
693723 if ( ! nodeRunResult ) return ;
694724
725+ // Store debug data
726+ if ( isDebugMode ) {
727+ if ( status === 'run' ) {
728+ this . debugNodeResponses [ node . nodeId ] = {
729+ nodeId : node . nodeId ,
730+ type : 'run' ,
731+ interactiveResponse : nodeRunResult . result [ DispatchNodeResponseKeyEnum . interactive ] ,
732+ response : nodeRunResult . result [ DispatchNodeResponseKeyEnum . nodeResponse ]
733+ } ;
734+ } else if ( status === 'skip' ) {
735+ this . debugNodeResponses [ node . nodeId ] = {
736+ nodeId : node . nodeId ,
737+ type : 'skip' ,
738+ response : nodeRunResult . result [ DispatchNodeResponseKeyEnum . nodeResponse ]
739+ } ;
740+ }
741+ }
742+ // 如果一个节点 active 运行了,则需要把它从 skip queue 里删除
743+ if ( status === 'run' ) {
744+ this . skipNodeQueue . delete ( node . nodeId ) ;
745+ }
746+
695747 /*
696748 特殊情况:
697749 通过 skipEdges 可以判断是运行了分支节点。
@@ -704,12 +756,20 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
704756 skippedNodeIdList . add ( node . nodeId ) ;
705757 }
706758
759+ // Update the node output at the end of the run and get the next nodes
760+ const { nextStepActiveNodes, nextStepSkipNodes } = nodeOutput (
761+ nodeRunResult . node ,
762+ nodeRunResult . result
763+ ) ;
764+
765+ nextStepSkipNodes . forEach ( ( node ) => {
766+ this . addSkipNode ( node , skippedNodeIdList ) ;
767+ } ) ;
768+
707769 // In the current version, only one interactive node is allowed at the same time
708- const interactiveResponse = nodeRunResult . result ?. [ DispatchNodeResponseKeyEnum . interactive ] ;
770+ const interactiveResponse = nodeRunResult . result [ DispatchNodeResponseKeyEnum . interactive ] ;
709771 if ( interactiveResponse ) {
710- pushStore ( nodeRunResult . result ) ;
711-
712- if ( data . mode === 'debug' ) {
772+ if ( isDebugMode ) {
713773 this . debugNextStepRunNodes = this . debugNextStepRunNodes . concat ( [ nodeRunResult . node ] ) ;
714774 }
715775
@@ -718,22 +778,14 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
718778 interactiveResponse
719779 } ;
720780 return ;
781+ } else if ( isDebugMode ) {
782+ // Debug 模式下一步时候,会自己增加 activeNode
783+ this . debugNextStepRunNodes = this . debugNextStepRunNodes . concat ( nextStepActiveNodes ) ;
784+ } else {
785+ nextStepActiveNodes . forEach ( ( node ) => {
786+ this . addActiveNode ( node . nodeId ) ;
787+ } ) ;
721788 }
722-
723- // Update the node output at the end of the run and get the next nodes
724- const { nextStepActiveNodes, nextStepSkipNodes } = nodeOutput (
725- nodeRunResult . node ,
726- nodeRunResult . result
727- ) ;
728-
729- nextStepSkipNodes . forEach ( ( node ) => {
730- this . addSkipNode ( node , skippedNodeIdList ) ;
731- } ) ;
732-
733- // Run next nodes
734- nextStepActiveNodes . forEach ( ( node ) => {
735- this . addActiveNode ( node . nodeId ) ;
736- } ) ;
737789 }
738790
739791 /* Have interactive result, computed edges and node outputs */
@@ -760,6 +812,10 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
760812
761813 const interactiveResult : WorkflowInteractiveResponseType = {
762814 ...interactiveResponse ,
815+ skipNodeQueue : Array . from ( this . skipNodeQueue . values ( ) ) . map ( ( item ) => ( {
816+ id : item . node . nodeId ,
817+ skippedNodeIdList : Array . from ( item . skippedNodeIdList )
818+ } ) ) ,
763819 entryNodeIds,
764820 memoryEdges : runtimeEdges . map ( ( edge ) => ( {
765821 ...edge ,
@@ -781,6 +837,22 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
781837 interactive : interactiveResult
782838 } ;
783839 }
840+ getDebugResponse ( ) : WorkflowDebugResponse {
841+ const entryNodeIds = this . debugNextStepRunNodes . map ( ( item ) => item . nodeId ) ;
842+
843+ return {
844+ memoryEdges : runtimeEdges . map ( ( edge ) => ( {
845+ ...edge ,
846+ status : entryNodeIds . includes ( edge . target ) ? 'active' : edge . status
847+ } ) ) ,
848+ entryNodeIds,
849+ nodeResponses : this . debugNodeResponses ,
850+ skipNodeQueue : Array . from ( this . skipNodeQueue . values ( ) ) . map ( ( item ) => ( {
851+ id : item . node . nodeId ,
852+ skippedNodeIdList : Array . from ( item . skippedNodeIdList )
853+ } ) )
854+ } ;
855+ }
784856 }
785857
786858 // Start process width initInput
@@ -799,7 +871,8 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
799871
800872 const workflowQueue = await new Promise < WorkflowQueue > ( ( resolve ) => {
801873 const workflowQueue = new WorkflowQueue ( {
802- resolve
874+ resolve,
875+ defaultSkipNodeQueue
803876 } ) ;
804877
805878 entryNodes . forEach ( ( node ) => {
@@ -833,11 +906,7 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
833906 return {
834907 flowResponses : workflowQueue . chatResponses ,
835908 flowUsages : workflowQueue . chatNodeUsages ,
836- debugResponse : {
837- finishedNodes : runtimeNodes ,
838- finishedEdges : runtimeEdges ,
839- nextStepRunNodes : workflowQueue . debugNextStepRunNodes
840- } ,
909+ debugResponse : workflowQueue . getDebugResponse ( ) ,
841910 workflowInteractiveResponse : interactiveResult ,
842911 [ DispatchNodeResponseKeyEnum . runTimes ] : workflowQueue . workflowRunTimes ,
843912 [ DispatchNodeResponseKeyEnum . assistantResponses ] : mergeAssistantResponseAnswerText (
0 commit comments