diff --git a/web/app/components/workflow-app/hooks/use-workflow-run.ts b/web/app/components/workflow-app/hooks/use-workflow-run.ts index 10155f6128..347b03f64c 100644 --- a/web/app/components/workflow-app/hooks/use-workflow-run.ts +++ b/web/app/components/workflow-app/hooks/use-workflow-run.ts @@ -44,6 +44,7 @@ export const useWorkflowRun = () => { handleWorkflowFailed, handleWorkflowNodeStarted, handleWorkflowNodeFinished, + handleWorkflowNodeHumanInputRequired, handleWorkflowNodeIterationStarted, handleWorkflowNodeIterationNext, handleWorkflowNodeIterationFinished, @@ -54,6 +55,7 @@ export const useWorkflowRun = () => { handleWorkflowAgentLog, handleWorkflowTextChunk, handleWorkflowTextReplace, + handleWorkflowSuspended, } = useWorkflowRunEvent() const handleBackupDraft = useCallback(() => { @@ -138,6 +140,8 @@ export const useWorkflowRun = () => { onNodeRetry, onAgentLog, onError, + onWorkflowSuspended, + onHumanInputRequired, ...restCallback } = callback || {} workflowStore.setState({ historyWorkflowData: undefined }) @@ -304,6 +308,16 @@ export const useWorkflowRun = () => { onTTSEnd: (messageId: string, audio: string) => { player.playAudioWithAudio(audio, false) }, + onWorkflowSuspended: (params) => { + handleWorkflowSuspended() + if (onWorkflowSuspended) + onWorkflowSuspended(params) + }, + onHumanInputRequired: (params) => { + handleWorkflowNodeHumanInputRequired(params) + if (onHumanInputRequired) + onHumanInputRequired(params) + }, ...restCallback, }, ) diff --git a/web/app/components/workflow/hooks/use-workflow-run-event/index.ts b/web/app/components/workflow/hooks/use-workflow-run-event/index.ts index 67bc6c15ef..b8b7656376 100644 --- a/web/app/components/workflow/hooks/use-workflow-run-event/index.ts +++ b/web/app/components/workflow/hooks/use-workflow-run-event/index.ts @@ -13,3 +13,5 @@ export * from './use-workflow-node-retry' export * from './use-workflow-text-chunk' export * from './use-workflow-text-replace' export * from './use-workflow-agent-log' +export * from './use-workflow-suspended' +export * from './use-workflow-node-human-input-required' diff --git a/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-human-input-required.ts b/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-human-input-required.ts new file mode 100644 index 0000000000..5b83f1548f --- /dev/null +++ b/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-human-input-required.ts @@ -0,0 +1,44 @@ +import { useCallback } from 'react' +import { + useStoreApi, +} from 'reactflow' +import produce from 'immer' +import { useWorkflowStore } from '@/app/components/workflow/store' +import type { HumanInputRequiredResponse } from '@/types/workflow' +import { NodeRunningStatus } from '@/app/components/workflow/types' +import { WorkflowRunningStatus } from '@/app/components/workflow/types' + +export const useWorkflowNodeHumanInputRequired = () => { + const workflowStore = useWorkflowStore() + const store = useStoreApi() + + const handleWorkflowNodeHumanInputRequired = useCallback((params: HumanInputRequiredResponse) => { + const { data } = params + const { + workflowRunningData, + setWorkflowRunningData, + } = workflowStore.getState() + const { + getNodes, + setNodes, + } = store.getState() + const nodes = getNodes() + const currentNodeIndex = nodes.findIndex(node => node.id === data.node_id) + const newNodes = produce(nodes, (draft) => { + draft[currentNodeIndex].data._runningStatus = NodeRunningStatus.Suspended + // draft[currentNodeIndex].data._waitingRun = false + }) + setNodes(newNodes) + + setWorkflowRunningData(produce(workflowRunningData!, (draft) => { + draft.result = { + ...draft.result, + status: WorkflowRunningStatus.Suspended, + } + })) + }, [workflowStore]) + + return { + handleWorkflowNodeHumanInputRequired, + } +} diff --git a/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-run-event.ts b/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-run-event.ts index 64883076cd..42b0bb2f1f 100644 --- a/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-run-event.ts +++ b/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-run-event.ts @@ -3,6 +3,7 @@ import { useWorkflowFailed, useWorkflowFinished, useWorkflowNodeFinished, + useWorkflowNodeHumanInputRequired, useWorkflowNodeIterationFinished, useWorkflowNodeIterationNext, useWorkflowNodeIterationStarted, @@ -12,6 +13,7 @@ import { useWorkflowNodeRetry, useWorkflowNodeStarted, useWorkflowStarted, + useWorkflowSuspended, useWorkflowTextChunk, useWorkflowTextReplace, } from '.' @@ -32,6 +34,8 @@ export const useWorkflowRunEvent = () => { const { handleWorkflowTextChunk } = useWorkflowTextChunk() const { handleWorkflowTextReplace } = useWorkflowTextReplace() const { handleWorkflowAgentLog } = useWorkflowAgentLog() + const { handleWorkflowSuspended } = useWorkflowSuspended() + const { handleWorkflowNodeHumanInputRequired } = useWorkflowNodeHumanInputRequired() return { handleWorkflowStarted, @@ -49,5 +53,7 @@ export const useWorkflowRunEvent = () => { handleWorkflowTextChunk, handleWorkflowTextReplace, handleWorkflowAgentLog, + handleWorkflowSuspended, + handleWorkflowNodeHumanInputRequired, } } diff --git a/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-suspended.ts b/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-suspended.ts new file mode 100644 index 0000000000..3fc4b480c3 --- /dev/null +++ b/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-suspended.ts @@ -0,0 +1,26 @@ +import { useCallback } from 'react' +import produce from 'immer' +import { useWorkflowStore } from '@/app/components/workflow/store' +import { WorkflowRunningStatus } from '@/app/components/workflow/types' + +export const useWorkflowSuspended = () => { + const workflowStore = useWorkflowStore() + + const handleWorkflowSuspended = useCallback(() => { + const { + workflowRunningData, + setWorkflowRunningData, + } = workflowStore.getState() + + setWorkflowRunningData(produce(workflowRunningData!, (draft) => { + draft.result = { + ...draft.result, + status: WorkflowRunningStatus.Suspended, + } + })) + }, [workflowStore]) + + return { + handleWorkflowSuspended, + } +} diff --git a/web/app/components/workflow/panel/inputs-panel.tsx b/web/app/components/workflow/panel/inputs-panel.tsx index c631fa2b67..a2bff2b5ba 100644 --- a/web/app/components/workflow/panel/inputs-panel.tsx +++ b/web/app/components/workflow/panel/inputs-panel.tsx @@ -98,10 +98,7 @@ const InputsPanel = ({ onRun }: Props) => { }, [files, handleRun, initialInputs, onRun, variables, checkInputsForm]) const canRun = useMemo(() => { - if (files?.some(item => (item.transfer_method as any) === TransferMethod.local_file && !item.upload_file_id)) - return false - - return true + return !(files?.some(item => (item.transfer_method as any) === TransferMethod.local_file && !item.upload_file_id)) }, [files]) return ( diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts index 325e622668..db3a4ef576 100644 --- a/web/app/components/workflow/types.ts +++ b/web/app/components/workflow/types.ts @@ -341,6 +341,7 @@ export enum NodeRunningStatus { Exception = 'exception', Retry = 'retry', Stopped = 'stopped', + Suspended = 'suspended', } export type OnNodeAdd = (