feat: add workflow resume functionality and enhance handling of HumanInput node in workflow events

This commit is contained in:
twwu 2025-12-30 18:30:32 +08:00
parent 44a688cb81
commit 0c69466b0f
7 changed files with 52 additions and 14 deletions

View File

@ -91,6 +91,7 @@ export const useWorkflowRun = () => {
handleWorkflowTextChunk,
handleWorkflowTextReplace,
handleWorkflowPaused,
handleWorkflowResume,
} = useWorkflowRunEvent()
const handleBackupDraft = useCallback(() => {
@ -376,13 +377,13 @@ export const useWorkflowRun = () => {
const baseSseOptions: IOtherOptions = {
...restCallback,
onWorkflowStarted: (params) => {
const state = workflowStore.getState()
if (state.workflowRunningData) {
state.setWorkflowRunningData(produce(state.workflowRunningData, (draft) => {
draft.resultText = ''
}))
const { is_resumption } = params.data
if (is_resumption) {
handleWorkflowResume()
}
else {
handleWorkflowStarted(params)
}
handleWorkflowStarted(params)
if (onWorkflowStarted)
onWorkflowStarted(params)
@ -801,7 +802,7 @@ export const useWorkflowRun = () => {
},
finalCallbacks,
)
}, [store, doSyncWorkflowDraft, workflowStore, pathname, handleWorkflowFailed, flowId, handleWorkflowStarted, handleWorkflowFinished, fetchInspectVars, invalidAllLastRun, handleWorkflowNodeStarted, handleWorkflowNodeFinished, handleWorkflowNodeIterationStarted, handleWorkflowNodeIterationNext, handleWorkflowNodeIterationFinished, handleWorkflowNodeLoopStarted, handleWorkflowNodeLoopNext, handleWorkflowNodeLoopFinished, handleWorkflowNodeRetry, handleWorkflowAgentLog, handleWorkflowTextChunk, handleWorkflowTextReplace, handleWorkflowPaused, handleWorkflowNodeHumanInputRequired])
}, [store, doSyncWorkflowDraft, workflowStore, pathname, handleWorkflowFailed, flowId, handleWorkflowResume, handleWorkflowStarted, handleWorkflowFinished, fetchInspectVars, invalidAllLastRun, handleWorkflowNodeStarted, handleWorkflowNodeFinished, handleWorkflowNodeIterationStarted, handleWorkflowNodeIterationNext, handleWorkflowNodeIterationFinished, handleWorkflowNodeLoopStarted, handleWorkflowNodeLoopNext, handleWorkflowNodeLoopFinished, handleWorkflowNodeRetry, handleWorkflowAgentLog, handleWorkflowTextChunk, handleWorkflowTextReplace, handleWorkflowPaused, handleWorkflowNodeHumanInputRequired])
const handleStopRun = useCallback((taskId: string) => {
const setStoppedState = () => {

View File

@ -49,7 +49,8 @@ export const useWorkflowNodeFinished = () => {
if (data.node_type === BlockEnum.QuestionClassifier)
currentNode.data._runningBranchId = data?.outputs?.class_id
// todo: add human-input node support
if (data.node_type === BlockEnum.HumanInput)
currentNode.data._runningBranchId = data?.outputs?.__action_id
}
})
setNodes(newNodes)

View File

@ -0,0 +1,26 @@
import { produce } from 'immer'
import { useCallback } from 'react'
import { useWorkflowStore } from '@/app/components/workflow/store'
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
export const useWorkflowResume = () => {
const workflowStore = useWorkflowStore()
const handleWorkflowResume = useCallback(() => {
const {
workflowRunningData,
setWorkflowRunningData,
} = workflowStore.getState()
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
draft.result = {
...draft.result,
status: WorkflowRunningStatus.Running,
}
}))
}, [workflowStore])
return {
handleWorkflowResume,
}
}

View File

@ -17,6 +17,7 @@ import {
useWorkflowTextChunk,
useWorkflowTextReplace,
} from '.'
import { useWorkflowResume } from './use-workflow-resume'
export const useWorkflowRunEvent = () => {
const { handleWorkflowStarted } = useWorkflowStarted()
@ -36,6 +37,7 @@ export const useWorkflowRunEvent = () => {
const { handleWorkflowAgentLog } = useWorkflowAgentLog()
const { handleWorkflowPaused } = useWorkflowPaused()
const { handleWorkflowNodeHumanInputRequired } = useWorkflowNodeHumanInputRequired()
const { handleWorkflowResume } = useWorkflowResume()
return {
handleWorkflowStarted,
@ -55,5 +57,6 @@ export const useWorkflowRunEvent = () => {
handleWorkflowAgentLog,
handleWorkflowPaused,
handleWorkflowNodeHumanInputRequired,
handleWorkflowResume,
}
}

View File

@ -30,6 +30,7 @@ export const useWorkflowStarted = () => {
...data,
status: WorkflowRunningStatus.Running,
}
draft.resultText = ''
}))
const nodes = getNodes()
const newNodes = produce(nodes, (draft) => {

View File

@ -351,12 +351,17 @@ export const useChat = (
onError() {
handleResponding(false)
},
onWorkflowStarted: ({ workflow_run_id, task_id }) => {
taskIdRef.current = task_id
responseItem.workflow_run_id = workflow_run_id
responseItem.workflowProcess = {
status: WorkflowRunningStatus.Running,
tracing: [],
onWorkflowStarted: ({ workflow_run_id, task_id, data: { is_resumption } }) => {
if (is_resumption) {
responseItem.workflowProcess!.status = WorkflowRunningStatus.Running
}
else {
taskIdRef.current = task_id
responseItem.workflow_run_id = workflow_run_id
responseItem.workflowProcess = {
status: WorkflowRunningStatus.Running,
tracing: [],
}
}
updateCurrentQAOnTree({
placeholderQuestionId,

View File

@ -165,6 +165,7 @@ export type WorkflowStartedResponse = {
id: string
workflow_id: string
created_at: number
is_resumption: boolean
}
}