Skip to content

Commit 7cd4a7c

Browse files
committed
feat: implement human input form timeout handling and enhance expiration time display
1 parent 94671d4 commit 7cd4a7c

File tree

20 files changed

+156
-43
lines changed

20 files changed

+156
-43
lines changed

web/app/components/app/text-generate/item/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({
215215
else
216216
switchTab('DETAIL')
217217
}, [workflowProcessData?.files?.length, workflowProcessData?.resultText, workflowProcessData?.humanInputFormDataList, workflowProcessData?.humanInputFilledFormDataList])
218-
const handleSubmitHumanInputForm = useCallback(async (formToken: string, formData: any) => {
218+
const handleSubmitHumanInputForm = useCallback(async (formToken: string, formData: { inputs: Record<string, string>, action: string }) => {
219219
if (appSourceType === AppSourceType.installedApp)
220220
await submitHumanInputFormService(formToken, formData)
221221
else

web/app/components/base/chat/chat/answer/human-input-content/expiration-time.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
'use client'
2+
import { RiAlertFill, RiTimeLine } from '@remixicon/react'
23
import { useTranslation } from 'react-i18next'
34
import { useLocale } from '@/context/i18n'
5+
import { cn } from '@/utils/classnames'
46
import { getRelativeTime, isRelativeTimeSameOrAfter } from './utils'
57

68
type ExpirationTimeProps = {
@@ -16,10 +18,27 @@ const ExpirationTime = ({
1618
const isSameOrAfter = isRelativeTimeSameOrAfter(expirationTime)
1719

1820
return (
19-
<div className="system-xs-regular mt-1 text-text-tertiary">
20-
{isSameOrAfter
21-
? t('humanInput.expirationTimeNowOrFuture', { relativeTime, ns: 'share' })
22-
: t('humanInput.expirationTimePast', { relativeTime, ns: 'share' })}
21+
<div
22+
className={cn(
23+
'system-xs-regular mt-1 flex items-center gap-x-1 text-text-tertiary',
24+
isSameOrAfter && 'text-text-warning',
25+
)}
26+
>
27+
{
28+
isSameOrAfter
29+
? (
30+
<>
31+
<RiTimeLine className="size-3.5" />
32+
<span>{t('humanInput.expirationTimeNowOrFuture', { relativeTime, ns: 'share' })}</span>
33+
</>
34+
)
35+
: (
36+
<>
37+
<RiAlertFill className="size-3.5" />
38+
<span>{t('humanInput.expiredTip', { ns: 'share' })}</span>
39+
</>
40+
)
41+
}
2342
</div>
2443
)
2544
}

web/app/components/base/chat/chat/answer/human-input-content/human-input-form.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ const HumanInputForm = ({
1818
const [inputs, setInputs] = useState(defaultInputs)
1919
const [isSubmitting, setIsSubmitting] = useState(false)
2020

21-
const handleInputsChange = useCallback((name: string, value: any) => {
21+
const handleInputsChange = useCallback((name: string, value: string) => {
2222
setInputs(prev => ({
2323
...prev,
2424
[name]: value,
2525
}))
2626
}, [])
2727

28-
const submit = async (formToken: string, actionID: string, inputs: Record<string, any>) => {
28+
const submit = async (formToken: string, actionID: string, inputs: Record<string, string>) => {
2929
setIsSubmitting(true)
3030
await onSubmit?.(formToken, { inputs, action: actionID })
3131
setIsSubmitting(false)

web/app/components/base/chat/chat/answer/human-input-content/type.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ export type UnsubmittedHumanInputContentProps = {
1111
showEmailTip?: boolean
1212
isEmailDebugMode?: boolean
1313
showDebugModeTip?: boolean
14-
showTimeout?: boolean
15-
expirationTime?: number
16-
onSubmit?: (formToken: string, data: any) => Promise<void>
14+
onSubmit?: (formToken: string, data: { inputs: Record<string, string>, action: string }) => Promise<void>
1715
}
1816

1917
export type SubmittedHumanInputContentProps = {
@@ -22,12 +20,12 @@ export type SubmittedHumanInputContentProps = {
2220

2321
export type HumanInputFormProps = {
2422
formData: HumanInputFormData
25-
onSubmit?: (formToken: string, data: any) => Promise<void>
23+
onSubmit?: (formToken: string, data: { inputs: Record<string, string>, action: string }) => Promise<void>
2624
}
2725

2826
export type ContentItemProps = {
2927
content: string
3028
formInputFields: FormInputItem[]
3129
inputs: Record<string, string>
32-
onInputChange: (name: string, value: any) => void
30+
onInputChange: (name: string, value: string) => void
3331
}

web/app/components/base/chat/chat/answer/human-input-content/unsubmitted.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ export const UnsubmittedHumanInputContent = ({
88
showEmailTip = false,
99
isEmailDebugMode = false,
1010
showDebugModeTip = false,
11-
showTimeout = false,
12-
expirationTime,
1311
onSubmit,
1412
}: UnsubmittedHumanInputContentProps) => {
13+
const { expiration_time } = formData
14+
1515
return (
1616
<>
1717
{/* Form */}
@@ -27,9 +27,9 @@ export const UnsubmittedHumanInputContent = ({
2727
showDebugModeTip={showDebugModeTip}
2828
/>
2929
)}
30-
{/* Timeout */}
31-
{showTimeout && typeof expirationTime === 'number' && (
32-
<ExpirationTime expirationTime={expirationTime} />
30+
{/* Expiration Time */}
31+
{typeof expiration_time === 'number' && (
32+
<ExpirationTime expirationTime={expiration_time} />
3333
)}
3434
</>
3535
)

web/app/components/base/chat/chat/answer/human-input-form-list.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { DeliveryMethod } from '@/app/components/workflow/nodes/human-input/types'
1+
import type { DeliveryMethod, HumanInputNodeType } from '@/app/components/workflow/nodes/human-input/types'
2+
import type { Node } from '@/app/components/workflow/types'
23
import type { HumanInputFormData } from '@/types/workflow'
34
import { useMemo } from 'react'
45
import { DeliveryMethodType } from '@/app/components/workflow/nodes/human-input/types'
@@ -7,8 +8,8 @@ import { UnsubmittedHumanInputContent } from './human-input-content/unsubmitted'
78

89
type HumanInputFormListProps = {
910
humanInputFormDataList: HumanInputFormData[]
10-
onHumanInputFormSubmit?: (formToken: string, formData: any) => Promise<void>
11-
getHumanInputNodeData?: (nodeID: string) => any
11+
onHumanInputFormSubmit?: (formToken: string, formData: { inputs: Record<string, string>, action: string }) => Promise<void>
12+
getHumanInputNodeData?: (nodeID: string) => Node<HumanInputNodeType> | undefined
1213
}
1314

1415
const HumanInputFormList = ({

web/app/components/base/chat/chat/hooks.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,14 @@ export const useChat = (
527527
}
528528
})
529529
},
530+
onHumanInputFormTimeout: ({ data: humanInputFormTimeoutData }) => {
531+
updateChatTreeNode(messageId, (responseItem) => {
532+
if (responseItem.humanInputFormDataList?.length) {
533+
const currentFormIndex = responseItem.humanInputFormDataList.findIndex(item => item.node_id === humanInputFormTimeoutData.node_id)
534+
responseItem.humanInputFormDataList[currentFormIndex].expiration_time = humanInputFormTimeoutData.expiration_time
535+
}
536+
})
537+
},
530538
onWorkflowPaused: ({ data: workflowPausedData }) => {
531539
const resumeUrl = `/workflow/${workflowPausedData.workflow_run_id}/events`
532540
sseGet(
@@ -1089,6 +1097,18 @@ export const useChat = (
10891097
parentId: data.parent_message_id,
10901098
})
10911099
},
1100+
onHumanInputFormTimeout: ({ data: humanInputFormTimeoutData }) => {
1101+
if (responseItem.humanInputFormDataList?.length) {
1102+
const currentFormIndex = responseItem.humanInputFormDataList!.findIndex(item => item.node_id === humanInputFormTimeoutData.node_id)
1103+
responseItem.humanInputFormDataList[currentFormIndex].expiration_time = humanInputFormTimeoutData.expiration_time
1104+
}
1105+
updateCurrentQAOnTree({
1106+
placeholderQuestionId,
1107+
questionItem,
1108+
responseItem,
1109+
parentId: data.parent_message_id,
1110+
})
1111+
},
10921112
onWorkflowPaused: ({ data: workflowPausedData }) => {
10931113
const url = `/workflow/${workflowPausedData.workflow_run_id}/events`
10941114
sseGet(

web/app/components/workflow-app/hooks/use-workflow-run.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export const useWorkflowRun = () => {
8181
handleWorkflowNodeFinished,
8282
handleWorkflowNodeHumanInputRequired,
8383
handleWorkflowNodeHumanInputFormFilled,
84+
handleWorkflowNodeHumanInputFormTimeout,
8485
handleWorkflowNodeIterationStarted,
8586
handleWorkflowNodeIterationNext,
8687
handleWorkflowNodeIterationFinished,
@@ -182,6 +183,7 @@ export const useWorkflowRun = () => {
182183
onWorkflowPaused,
183184
onHumanInputRequired,
184185
onHumanInputFormFilled,
186+
onHumanInputFormTimeout,
185187
onCompleted,
186188
...restCallback
187189
} = callback || {}
@@ -513,6 +515,11 @@ export const useWorkflowRun = () => {
513515
if (onHumanInputFormFilled)
514516
onHumanInputFormFilled(params)
515517
},
518+
onHumanInputFormTimeout: (params) => {
519+
handleWorkflowNodeHumanInputFormTimeout(params)
520+
if (onHumanInputFormTimeout)
521+
onHumanInputFormTimeout(params)
522+
},
516523
onError: wrappedOnError,
517524
onCompleted: wrappedOnCompleted,
518525
}
@@ -627,6 +634,7 @@ export const useWorkflowRun = () => {
627634
baseSseOptions.onAgentLog,
628635
baseSseOptions.onHumanInputRequired,
629636
baseSseOptions.onHumanInputFormFilled,
637+
baseSseOptions.onHumanInputFormTimeout,
630638
baseSseOptions.onWorkflowPaused,
631639
baseSseOptions.onDataSourceNodeProcessing,
632640
baseSseOptions.onDataSourceNodeCompleted,
@@ -814,6 +822,11 @@ export const useWorkflowRun = () => {
814822
if (onHumanInputFormFilled)
815823
onHumanInputFormFilled(params)
816824
},
825+
onHumanInputFormTimeout: (params) => {
826+
handleWorkflowNodeHumanInputFormTimeout(params)
827+
if (onHumanInputFormTimeout)
828+
onHumanInputFormTimeout(params)
829+
},
817830
...restCallback,
818831
}
819832

@@ -824,7 +837,7 @@ export const useWorkflowRun = () => {
824837
},
825838
finalCallbacks,
826839
)
827-
}, [store, doSyncWorkflowDraft, workflowStore, pathname, handleWorkflowFailed, flowId, handleWorkflowStarted, handleWorkflowFinished, fetchInspectVars, invalidAllLastRun, handleWorkflowNodeStarted, handleWorkflowNodeFinished, handleWorkflowNodeIterationStarted, handleWorkflowNodeIterationNext, handleWorkflowNodeIterationFinished, handleWorkflowNodeLoopStarted, handleWorkflowNodeLoopNext, handleWorkflowNodeLoopFinished, handleWorkflowNodeRetry, handleWorkflowAgentLog, handleWorkflowTextChunk, handleWorkflowTextReplace, handleWorkflowPaused, handleWorkflowNodeHumanInputRequired, handleWorkflowNodeHumanInputFormFilled])
840+
}, [store, doSyncWorkflowDraft, workflowStore, pathname, handleWorkflowFailed, flowId, handleWorkflowStarted, handleWorkflowFinished, fetchInspectVars, invalidAllLastRun, handleWorkflowNodeStarted, handleWorkflowNodeFinished, handleWorkflowNodeIterationStarted, handleWorkflowNodeIterationNext, handleWorkflowNodeIterationFinished, handleWorkflowNodeLoopStarted, handleWorkflowNodeLoopNext, handleWorkflowNodeLoopFinished, handleWorkflowNodeRetry, handleWorkflowAgentLog, handleWorkflowTextChunk, handleWorkflowTextReplace, handleWorkflowPaused, handleWorkflowNodeHumanInputRequired, handleWorkflowNodeHumanInputFormFilled, handleWorkflowNodeHumanInputFormTimeout])
828841

829842
const handleStopRun = useCallback((taskId: string) => {
830843
const setStoppedState = () => {

web/app/components/workflow/hooks/use-workflow-run-event/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from './use-workflow-failed'
33
export * from './use-workflow-finished'
44
export * from './use-workflow-node-finished'
55
export * from './use-workflow-node-human-input-form-filled'
6+
export * from './use-workflow-node-human-input-form-timeout'
67
export * from './use-workflow-node-human-input-required'
78
export * from './use-workflow-node-iteration-finished'
89
export * from './use-workflow-node-iteration-next'
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { HumanInputFormTimeoutResponse } from '@/types/workflow'
2+
import { produce } from 'immer'
3+
import { useCallback } from 'react'
4+
import { useWorkflowStore } from '@/app/components/workflow/store'
5+
6+
export const useWorkflowNodeHumanInputFormTimeout = () => {
7+
const workflowStore = useWorkflowStore()
8+
9+
const handleWorkflowNodeHumanInputFormTimeout = useCallback((params: HumanInputFormTimeoutResponse) => {
10+
const { data } = params
11+
const {
12+
workflowRunningData,
13+
setWorkflowRunningData,
14+
} = workflowStore.getState()
15+
16+
const newWorkflowRunningData = produce(workflowRunningData!, (draft) => {
17+
if (draft.humanInputFormDataList?.length) {
18+
const currentFormIndex = draft.humanInputFormDataList.findIndex(item => item.node_id === data.node_id)
19+
draft.humanInputFormDataList[currentFormIndex].expiration_time = data.expiration_time
20+
}
21+
})
22+
setWorkflowRunningData(newWorkflowRunningData)
23+
}, [workflowStore])
24+
25+
return {
26+
handleWorkflowNodeHumanInputFormTimeout,
27+
}
28+
}

0 commit comments

Comments
 (0)