feat: Human Input Node (#32060)

The frontend and backend implementation for the human input node.

Co-authored-by: twwu <twwu@dify.ai>
Co-authored-by: JzoNg <jzongcode@gmail.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
Co-authored-by: zhsama <torvalds@linux.do>
This commit is contained in:
QuantumGhost
2026-02-09 14:57:23 +08:00
committed by GitHub
parent 56e3a55023
commit a1fc280102
474 changed files with 32667 additions and 2050 deletions

View File

@ -18,7 +18,7 @@ import {
useStore,
useWorkflowStore,
} from '../../store'
import { BlockEnum } from '../../types'
import { BlockEnum, WorkflowRunningStatus } from '../../types'
import ConversationVariableModal from './conversation-variable-modal'
import Empty from './empty'
import { useChat } from './hooks'
@ -84,7 +84,9 @@ const ChatWrapper = (
suggestedQuestions,
handleSend,
handleRestart,
setTargetMessageId,
handleSwitchSibling,
handleSubmitHumanInputForm,
getHumanInputNodeData,
} = useChat(
config,
{
@ -121,6 +123,22 @@ const ChatWrapper = (
doSend(editedQuestion ? editedQuestion.message : question.content, editedQuestion ? editedQuestion.files : question.message_files, true, isValidGeneratedAnswer(parentAnswer) ? parentAnswer : null)
}, [chatList, doSend])
const doSwitchSibling = useCallback((siblingMessageId: string) => {
handleSwitchSibling(siblingMessageId, {
onGetSuggestedQuestions: (messageId, getAbortController) => fetchSuggestedQuestions(appDetail!.id, messageId, getAbortController),
})
}, [handleSwitchSibling, appDetail])
const doHumanInputFormSubmit = useCallback(async (formToken: string, formData: any) => {
// Handle human input form submission
await handleSubmitHumanInputForm(formToken, formData)
}, [handleSubmitHumanInputForm])
const inputDisabled = useMemo(() => {
const latestMessage = chatList[chatList.length - 1]
return latestMessage?.isAnswer && (latestMessage.workflowProcess?.status === WorkflowRunningStatus.Paused)
}, [chatList])
const { eventEmitter } = useEventEmitterContextContext()
eventEmitter?.useSubscription((v: any) => {
if (v.type === EVENT_WORKFLOW_STOP)
@ -168,6 +186,8 @@ const ChatWrapper = (
inputsForm={(startVariables || []) as any}
onRegenerate={doRegenerate}
onStopResponding={handleStop}
onHumanInputFormSubmit={doHumanInputFormSubmit}
getHumanInputNodeData={getHumanInputNodeData}
chatNode={(
<>
{showInputsFieldsPanel && <UserInput />}
@ -182,7 +202,9 @@ const ChatWrapper = (
suggestedQuestions={suggestedQuestions}
showPromptLog
chatAnswerContainerInner="!pr-2"
switchSibling={setTargetMessageId}
switchSibling={doSwitchSibling}
inputDisabled={inputDisabled}
hideAvatar
/>
{showConversationVariableModal && (
<ConversationVariableModal