diff --git a/web/src/pages/agent/constant/index.tsx b/web/src/pages/agent/constant/index.tsx
index 581dd27de..3c8a5c8b8 100644
--- a/web/src/pages/agent/constant/index.tsx
+++ b/web/src/pages/agent/constant/index.tsx
@@ -624,7 +624,12 @@ export const initialVariableAssignerValues = {};
export const initialVariableAggregatorValues = { outputs: {}, groups: [] };
-export const initialLoopValues = { outputs: {} };
+export const initialLoopValues = {
+ loop_variables: [],
+ loop_termination_condition: [],
+ maximum_loop_count: 10,
+ outputs: {},
+};
export const CategorizeAnchorPointPositions = [
{ top: 1, right: 34 },
diff --git a/web/src/pages/agent/form-sheet/form-config-map.tsx b/web/src/pages/agent/form-sheet/form-config-map.tsx
index 37ab4cf2f..1b3576ffd 100644
--- a/web/src/pages/agent/form-sheet/form-config-map.tsx
+++ b/web/src/pages/agent/form-sheet/form-config-map.tsx
@@ -22,6 +22,7 @@ import IterationStartForm from '../form/iteration-start-from';
import Jin10Form from '../form/jin10-form';
import KeywordExtractForm from '../form/keyword-extract-form';
import ListOperationsForm from '../form/list-operations-form';
+import LoopForm from '../form/loop-form';
import MessageForm from '../form/message-form';
import ParserForm from '../form/parser-form';
import PubMedForm from '../form/pubmed-form';
@@ -191,8 +192,10 @@ export const FormConfigMap = {
[Operator.VariableAssigner]: {
component: VariableAssignerForm,
},
-
[Operator.VariableAggregator]: {
component: VariableAggregatorForm,
},
+ [Operator.Loop]: {
+ component: LoopForm,
+ },
};
diff --git a/web/src/pages/agent/form/iteration-form/index.tsx b/web/src/pages/agent/form/iteration-form/index.tsx
index c528fa720..61e16277d 100644
--- a/web/src/pages/agent/form/iteration-form/index.tsx
+++ b/web/src/pages/agent/form/iteration-form/index.tsx
@@ -9,7 +9,6 @@ import { FormWrapper } from '../components/form-wrapper';
import { Output } from '../components/output';
import { QueryVariable } from '../components/query-variable';
import { DynamicOutput } from './dynamic-output';
-import { DynamicVariables } from './dynamic-variables';
import { OutputArray } from './interface';
import { useValues } from './use-values';
import { useWatchFormChange } from './use-watch-form-change';
@@ -53,7 +52,6 @@ function IterationForm({ node }: INextOperatorForm) {
name="items_ref"
types={ArrayFields as any[]}
>
-
diff --git a/web/src/pages/agent/form/iteration-form/dynamic-variables.tsx b/web/src/pages/agent/form/loop-form/dynamic-variables.tsx
similarity index 98%
rename from web/src/pages/agent/form/iteration-form/dynamic-variables.tsx
rename to web/src/pages/agent/form/loop-form/dynamic-variables.tsx
index 62840d5a7..9a9b86d90 100644
--- a/web/src/pages/agent/form/iteration-form/dynamic-variables.tsx
+++ b/web/src/pages/agent/form/loop-form/dynamic-variables.tsx
@@ -67,7 +67,7 @@ function RadioButton({ value, onChange }: RadioButtonProps) {
const VariableTypeOptions = buildConversationVariableSelectOptions();
-const modeField = 'mode';
+const modeField = 'input_mode';
const ConstantValueMap = {
[TypesWithArray.Boolean]: 'yes',
@@ -85,8 +85,8 @@ export function DynamicVariables({
label,
tooltip,
keyField = 'variable',
- valueField = 'parameter',
- operatorField = 'operator',
+ valueField = 'value',
+ operatorField = 'type',
}: SelectKeysProps) {
const form = useFormContext();
const isDarkTheme = useIsDarkTheme();
diff --git a/web/src/pages/agent/form/loop-form/index.tsx b/web/src/pages/agent/form/loop-form/index.tsx
new file mode 100644
index 000000000..ff4acfc25
--- /dev/null
+++ b/web/src/pages/agent/form/loop-form/index.tsx
@@ -0,0 +1,54 @@
+import { Form } from '@/components/ui/form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { memo } from 'react';
+import { useForm } from 'react-hook-form';
+import { z } from 'zod';
+import { initialLoopValues } from '../../constant';
+import { useFormValues } from '../../hooks/use-form-values';
+import { useWatchFormChange } from '../../hooks/use-watch-form-change';
+import { INextOperatorForm } from '../../interface';
+import { FormWrapper } from '../components/form-wrapper';
+import { DynamicVariables } from './dynamic-variables';
+
+const FormSchema = z.object({
+ loop_variables: z.array(
+ z.object({
+ variable: z.string().optional(),
+ type: z.string().optional(),
+ value: z.string().or(z.number()).or(z.boolean()).optional(),
+ input_mode: z.string(),
+ }),
+ ),
+ loop_termination_condition: z.array(
+ z.object({
+ variable: z.string().optional(),
+ operator: z.string().optional(),
+ value: z.string().or(z.number()).or(z.boolean()).optional(),
+ input_mode: z.string(),
+ }),
+ ),
+});
+
+function LoopForm({ node }: INextOperatorForm) {
+ const defaultValues = useFormValues(initialLoopValues, node);
+
+ const form = useForm({
+ defaultValues: defaultValues,
+ resolver: zodResolver(FormSchema),
+ });
+
+ useWatchFormChange(node?.id, form, true);
+
+ return (
+
+ );
+}
+
+export default memo(LoopForm);