diff --git a/web/src/pages/agent/canvas/node/dropdown/next-step-dropdown.tsx b/web/src/pages/agent/canvas/node/dropdown/next-step-dropdown.tsx
index 3a18233a1..dfb6b12f1 100644
--- a/web/src/pages/agent/canvas/node/dropdown/next-step-dropdown.tsx
+++ b/web/src/pages/agent/canvas/node/dropdown/next-step-dropdown.tsx
@@ -67,7 +67,9 @@ function AccordionOperators() {
Dialogue
-
+
diff --git a/web/src/pages/agent/constant.tsx b/web/src/pages/agent/constant.tsx
index 26b028825..dd8a882d3 100644
--- a/web/src/pages/agent/constant.tsx
+++ b/web/src/pages/agent/constant.tsx
@@ -86,6 +86,7 @@ export enum Operator {
Agent = 'Agent',
Tool = 'Tool',
TavilySearch = 'TavilySearch',
+ UserFillUp = 'UserFillUp',
}
export const SwitchLogicOperatorOptions = ['and', 'or'];
@@ -696,6 +697,12 @@ export const initialAgentValues = {
},
};
+export const initialUserFillUpValues = {
+ enable_tips: true,
+ tips: '',
+ inputs: [],
+};
+
export enum TavilySearchDepth {
Basic = 'basic',
Advanced = 'advanced',
@@ -860,6 +867,7 @@ export const NodeMap = {
[Operator.Agent]: 'agentNode',
[Operator.Tool]: 'toolNode',
[Operator.TavilySearch]: 'ragNode',
+ [Operator.UserFillUp]: 'ragNode',
};
export enum BeginQueryType {
diff --git a/web/src/pages/agent/form-sheet/use-form-config-map.tsx b/web/src/pages/agent/form-sheet/use-form-config-map.tsx
index 08e2a125a..175205f64 100644
--- a/web/src/pages/agent/form-sheet/use-form-config-map.tsx
+++ b/web/src/pages/agent/form-sheet/use-form-config-map.tsx
@@ -38,6 +38,7 @@ import TavilyForm from '../form/tavily-form';
import TemplateForm from '../form/template-form';
import ToolForm from '../form/tool-form';
import TuShareForm from '../form/tushare-form';
+import UserFillUpForm from '../form/user-fill-up-form';
import WenCaiForm from '../form/wencai-form';
import WikipediaForm from '../form/wikipedia-form';
import YahooFinanceForm from '../form/yahoo-finance-form';
@@ -382,6 +383,11 @@ export function useFormConfigMap() {
defaultValues: {},
schema: z.object({}),
},
+ [Operator.UserFillUp]: {
+ component: UserFillUpForm,
+ defaultValues: {},
+ schema: z.object({}),
+ },
};
return FormConfigMap;
diff --git a/web/src/pages/agent/form/user-fill-up-form/index.tsx b/web/src/pages/agent/form/user-fill-up-form/index.tsx
new file mode 100644
index 000000000..240eed0e7
--- /dev/null
+++ b/web/src/pages/agent/form/user-fill-up-form/index.tsx
@@ -0,0 +1,155 @@
+import { Collapse } from '@/components/collapse';
+import { Button } from '@/components/ui/button';
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { Switch } from '@/components/ui/switch';
+import { Textarea } from '@/components/ui/textarea';
+import { FormTooltip } from '@/components/ui/tooltip';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { Plus } from 'lucide-react';
+import { useForm, useWatch } from 'react-hook-form';
+import { useTranslation } from 'react-i18next';
+import { z } from 'zod';
+import { INextOperatorForm } from '../../interface';
+import { ParameterDialog } from '../begin-form/parameter-dialog';
+import { QueryTable } from '../begin-form/query-table';
+import { useEditQueryRecord } from '../begin-form/use-edit-query';
+import { useValues } from './use-values';
+import { useWatchFormChange } from './use-watch-change';
+
+const UserFillUpForm = ({ node }: INextOperatorForm) => {
+ const { t } = useTranslation();
+
+ const values = useValues(node);
+
+ const FormSchema = z.object({
+ enable_tips: z.boolean().optional(),
+ tips: z.string().trim().optional(),
+ inputs: z
+ .array(
+ z.object({
+ key: z.string(),
+ type: z.string(),
+ value: z.string(),
+ optional: z.boolean(),
+ name: z.string(),
+ options: z.array(z.union([z.number(), z.string(), z.boolean()])),
+ }),
+ )
+ .optional(),
+ });
+
+ const form = useForm({
+ defaultValues: values,
+ resolver: zodResolver(FormSchema),
+ });
+
+ useWatchFormChange(node?.id, form);
+
+ const inputs = useWatch({ control: form.control, name: 'inputs' });
+
+ const {
+ ok,
+ currentRecord,
+ visible,
+ hideModal,
+ showModal,
+ otherThanCurrentQuery,
+ handleDeleteRecord,
+ } = useEditQueryRecord({
+ form,
+ node,
+ });
+
+ return (
+
+ );
+};
+
+export default UserFillUpForm;
diff --git a/web/src/pages/agent/form/user-fill-up-form/use-values.ts b/web/src/pages/agent/form/user-fill-up-form/use-values.ts
new file mode 100644
index 000000000..0af1c78c3
--- /dev/null
+++ b/web/src/pages/agent/form/user-fill-up-form/use-values.ts
@@ -0,0 +1,21 @@
+import { RAGFlowNodeType } from '@/interfaces/database/flow';
+import { isEmpty } from 'lodash';
+import { useMemo } from 'react';
+import { initialUserFillUpValues } from '../../constant';
+import { buildBeginInputListFromObject } from '../begin-form/utils';
+
+export function useValues(node?: RAGFlowNodeType) {
+ const values = useMemo(() => {
+ const formData = node?.data?.form;
+
+ if (isEmpty(formData)) {
+ return initialUserFillUpValues;
+ }
+
+ const inputs = buildBeginInputListFromObject(formData?.inputs);
+
+ return { ...(formData || {}), inputs };
+ }, [node?.data?.form]);
+
+ return values;
+}
diff --git a/web/src/pages/agent/form/user-fill-up-form/use-watch-change.ts b/web/src/pages/agent/form/user-fill-up-form/use-watch-change.ts
new file mode 100644
index 000000000..3dc451265
--- /dev/null
+++ b/web/src/pages/agent/form/user-fill-up-form/use-watch-change.ts
@@ -0,0 +1,31 @@
+import { omit } from 'lodash';
+import { useEffect } from 'react';
+import { UseFormReturn, useWatch } from 'react-hook-form';
+import { BeginQuery } from '../../interface';
+import useGraphStore from '../../store';
+
+function transferInputsArrayToObject(inputs: BeginQuery[] = []) {
+ return inputs.reduce>>((pre, cur) => {
+ pre[cur.key] = omit(cur, 'key');
+
+ return pre;
+ }, {});
+}
+
+export function useWatchFormChange(id?: string, form?: UseFormReturn) {
+ let values = useWatch({ control: form?.control });
+ const updateNodeForm = useGraphStore((state) => state.updateNodeForm);
+
+ useEffect(() => {
+ if (id && form?.formState.isDirty) {
+ values = form?.getValues();
+
+ const nextValues = {
+ ...values,
+ inputs: transferInputsArrayToObject(values.inputs),
+ };
+
+ updateNodeForm(id, nextValues);
+ }
+ }, [form?.formState.isDirty, id, updateNodeForm, values]);
+}
diff --git a/web/src/pages/agent/hooks/use-add-node.ts b/web/src/pages/agent/hooks/use-add-node.ts
index 25f75b383..c243f9773 100644
--- a/web/src/pages/agent/hooks/use-add-node.ts
+++ b/web/src/pages/agent/hooks/use-add-node.ts
@@ -43,6 +43,7 @@ import {
initialTavilyValues,
initialTemplateValues,
initialTuShareValues,
+ initialUserFillUpValues,
initialWaitingDialogueValues,
initialWenCaiValues,
initialWikipediaValues,
@@ -106,6 +107,7 @@ export const useInitializeOperatorParams = () => {
[Operator.Agent]: { ...initialAgentValues, llm_id: llmId },
[Operator.Tool]: {},
[Operator.TavilySearch]: initialTavilyValues,
+ [Operator.UserFillUp]: initialUserFillUpValues,
};
}, [llmId]);
diff --git a/web/src/pages/agent/operator-icon.tsx b/web/src/pages/agent/operator-icon.tsx
index 3c2479492..1547b6ca7 100644
--- a/web/src/pages/agent/operator-icon.tsx
+++ b/web/src/pages/agent/operator-icon.tsx
@@ -1,6 +1,6 @@
import { IconFont } from '@/components/icon-font';
import { cn } from '@/lib/utils';
-import { CirclePlay } from 'lucide-react';
+import { CirclePlay, MessageSquareMore } from 'lucide-react';
import { Operator } from './constant';
interface IProps {
@@ -19,6 +19,7 @@ export const OperatorIconMap = {
[Operator.Switch]: 'condition',
[Operator.Code]: 'code-set',
[Operator.Agent]: 'agent-ai',
+ [Operator.UserFillUp]: MessageSquareMore,
// [Operator.Relevant]: BranchesOutlined,
// [Operator.RewriteQuestion]: FormOutlined,
// [Operator.KeywordExtract]: KeywordIcon,