Skip to content

Commit 971197d

Browse files
authored
Feat: Set the outputs type of list operation. #10427 (#11366)
### What problem does this PR solve? Feat: Set the outputs type of list operation. #10427 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
1 parent 0884e9a commit 971197d

File tree

8 files changed

+148
-42
lines changed

8 files changed

+148
-42
lines changed

web/src/components/originui/number-input.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ interface NumberInputProps {
66
value?: number;
77
onChange?: (value: number) => void;
88
height?: number | string;
9+
min?: number;
910
}
1011

1112
const NumberInput: React.FC<NumberInputProps> = ({
1213
className,
1314
value: initialValue,
1415
onChange,
1516
height,
17+
min = 0,
1618
}) => {
1719
const [value, setValue] = useState<number>(() => {
1820
return initialValue ?? 0;
@@ -76,6 +78,7 @@ const NumberInput: React.FC<NumberInputProps> = ({
7678
onChange={handleChange}
7779
className="w-full flex-1 text-center bg-transparent focus:outline-none"
7880
style={style}
81+
min={min}
7982
/>
8083
<button
8184
type="button"

web/src/locales/en.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,7 @@ Example: https://fsn1.your-objectstorage.com`,
10621062
apiKeyPlaceholder:
10631063
'YOUR_API_KEY (obtained from https://serpapi.com/manage-api-key)',
10641064
flowStart: 'Start',
1065-
flowNum: 'Num',
1065+
flowNum: 'N',
10661066
test: 'Test',
10671067
extractDepth: 'Extract Depth',
10681068
format: 'Format',

web/src/pages/agent/constant/index.tsx

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
AgentStructuredOutputField,
99
CodeTemplateStrMap,
1010
ComparisonOperator,
11+
JsonSchemaDataType,
1112
Operator,
1213
ProgrammingLanguage,
1314
SwitchOperatorOptions,
@@ -610,15 +611,15 @@ export const initialListOperationsValues = {
610611
query: '',
611612
operations: ListOperations.TopN,
612613
outputs: {
613-
result: {
614-
type: 'Array<?>',
615-
},
616-
first: {
617-
type: '?',
618-
},
619-
last: {
620-
type: '?',
621-
},
614+
// result: {
615+
// type: 'Array<?>',
616+
// },
617+
// first: {
618+
// type: '?',
619+
// },
620+
// last: {
621+
// type: '?',
622+
// },
622623
},
623624
};
624625

@@ -874,3 +875,22 @@ export enum ExportFileType {
874875
Markdown = 'md',
875876
DOCX = 'docx',
876877
}
878+
879+
export enum TypesWithArray {
880+
String = 'string',
881+
Number = 'number',
882+
Boolean = 'boolean',
883+
Object = 'object',
884+
ArrayString = 'array<string>',
885+
ArrayNumber = 'array<number>',
886+
ArrayBoolean = 'array<boolean>',
887+
ArrayObject = 'array<object>',
888+
}
889+
890+
export const ArrayFields = [
891+
JsonSchemaDataType.Array,
892+
TypesWithArray.ArrayBoolean,
893+
TypesWithArray.ArrayNumber,
894+
TypesWithArray.ArrayString,
895+
TypesWithArray.ArrayObject,
896+
];

web/src/pages/agent/form/iteration-form/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
44
import { memo, useMemo } from 'react';
55
import { useForm, useWatch } from 'react-hook-form';
66
import { z } from 'zod';
7-
import { JsonSchemaDataType } from '../../constant';
7+
import { ArrayFields } from '../../constant';
88
import { INextOperatorForm } from '../../interface';
99
import { FormWrapper } from '../components/form-wrapper';
1010
import { Output } from '../components/output';
@@ -44,7 +44,7 @@ function IterationForm({ node }: INextOperatorForm) {
4444
<FormContainer>
4545
<QueryVariable
4646
name="items_ref"
47-
types={[JsonSchemaDataType.Array]}
47+
types={ArrayFields as any[]}
4848
></QueryVariable>
4949
</FormContainer>
5050
<DynamicOutput node={node}></DynamicOutput>

web/src/pages/agent/form/list-operations-form/index.tsx

Lines changed: 100 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,22 @@ import { Separator } from '@/components/ui/separator';
1313
import { useBuildSwitchOperatorOptions } from '@/hooks/logic-hooks/use-build-operator-options';
1414
import { buildOptions } from '@/utils/form';
1515
import { zodResolver } from '@hookform/resolvers/zod';
16-
import { memo } from 'react';
16+
import { memo, useCallback, useEffect, useMemo } from 'react';
1717
import { useForm, useWatch } from 'react-hook-form';
1818
import { useTranslation } from 'react-i18next';
1919
import { z } from 'zod';
2020
import {
21+
ArrayFields,
2122
DataOperationsOperatorOptions,
22-
JsonSchemaDataType,
2323
ListOperations,
2424
SortMethod,
2525
initialListOperationsValues,
2626
} from '../../constant';
2727
import { useFormValues } from '../../hooks/use-form-values';
28+
import { useGetVariableLabelOrTypeByValue } from '../../hooks/use-get-begin-query';
2829
import { useWatchFormChange } from '../../hooks/use-watch-form-change';
2930
import { INextOperatorForm } from '../../interface';
31+
import { getArrayElementType } from '../../utils';
3032
import { buildOutputList } from '../../utils/build-output-list';
3133
import { FormWrapper } from '../components/form-wrapper';
3234
import { Output, OutputSchema } from '../components/output';
@@ -36,7 +38,7 @@ import { QueryVariable } from '../components/query-variable';
3638
export const RetrievalPartialSchema = {
3739
query: z.string(),
3840
operations: z.string(),
39-
n: z.number().int().min(0).optional(),
41+
n: z.number().int().min(1).optional(),
4042
sort_method: z.string().optional(),
4143
filter: z
4244
.object({
@@ -47,26 +49,68 @@ export const RetrievalPartialSchema = {
4749
...OutputSchema,
4850
};
4951

52+
const NumFields = [
53+
ListOperations.TopN,
54+
ListOperations.Head,
55+
ListOperations.Tail,
56+
];
57+
58+
function showField(operations: string) {
59+
const showNum = NumFields.includes(operations as ListOperations);
60+
const showSortMethod = [ListOperations.Sort].includes(
61+
operations as ListOperations,
62+
);
63+
const showFilter = [ListOperations.Filter].includes(
64+
operations as ListOperations,
65+
);
66+
67+
return {
68+
showNum,
69+
showSortMethod,
70+
showFilter,
71+
};
72+
}
73+
5074
export const FormSchema = z.object(RetrievalPartialSchema);
5175

5276
export type ListOperationsFormSchemaType = z.infer<typeof FormSchema>;
5377

54-
const outputList = buildOutputList(initialListOperationsValues.outputs);
55-
5678
function ListOperationsForm({ node }: INextOperatorForm) {
5779
const { t } = useTranslation();
5880

81+
const { getType } = useGetVariableLabelOrTypeByValue();
82+
5983
const defaultValues = useFormValues(initialListOperationsValues, node);
6084

6185
const form = useForm<ListOperationsFormSchemaType>({
6286
defaultValues: defaultValues,
6387
mode: 'onChange',
6488
resolver: zodResolver(FormSchema),
65-
shouldUnregister: true,
89+
// shouldUnregister: true,
6690
});
6791

6892
const operations = useWatch({ control: form.control, name: 'operations' });
6993

94+
const query = useWatch({ control: form.control, name: 'query' });
95+
96+
const subType = getArrayElementType(getType(query));
97+
98+
const currentOutputs = useMemo(() => {
99+
return {
100+
result: {
101+
type: `Array<${subType}>`,
102+
},
103+
first: {
104+
type: subType,
105+
},
106+
last: {
107+
type: subType,
108+
},
109+
};
110+
}, [subType]);
111+
112+
const outputList = buildOutputList(currentOutputs);
113+
70114
const ListOperationsOptions = buildOptions(
71115
ListOperations,
72116
t,
@@ -79,9 +123,39 @@ function ListOperationsForm({ node }: INextOperatorForm) {
79123
`flow.SortMethodOptions`,
80124
true,
81125
);
126+
82127
const operatorOptions = useBuildSwitchOperatorOptions(
83128
DataOperationsOperatorOptions,
84129
);
130+
131+
const { showFilter, showNum, showSortMethod } = showField(operations);
132+
133+
const handleOperationsChange = useCallback(
134+
(operations: string) => {
135+
const { showFilter, showNum, showSortMethod } = showField(operations);
136+
137+
if (showNum) {
138+
form.setValue('n', 1, { shouldDirty: true });
139+
}
140+
141+
if (showSortMethod) {
142+
form.setValue('sort_method', SortMethodOptions.at(0)?.value, {
143+
shouldDirty: true,
144+
});
145+
}
146+
if (showFilter) {
147+
form.setValue('filter.operator', operatorOptions.at(0)?.value, {
148+
shouldDirty: true,
149+
});
150+
}
151+
},
152+
[SortMethodOptions, form, operatorOptions],
153+
);
154+
155+
useEffect(() => {
156+
form.setValue('outputs', currentOutputs, { shouldDirty: true });
157+
}, [currentOutputs, form]);
158+
85159
useWatchFormChange(node?.id, form, true);
86160

87161
return (
@@ -90,37 +164,46 @@ function ListOperationsForm({ node }: INextOperatorForm) {
90164
<QueryVariable
91165
name="query"
92166
className="flex-1"
93-
types={[JsonSchemaDataType.Array]}
167+
types={ArrayFields as any[]}
94168
></QueryVariable>
95169
<Separator />
96170
<RAGFlowFormItem name="operations" label={t('flow.operations')}>
97-
<SelectWithSearch options={ListOperationsOptions} />
171+
{(field) => (
172+
<SelectWithSearch
173+
options={ListOperationsOptions}
174+
value={field.value}
175+
onChange={(val) => {
176+
handleOperationsChange(val);
177+
field.onChange(val);
178+
}}
179+
/>
180+
)}
98181
</RAGFlowFormItem>
99-
{[
100-
ListOperations.TopN,
101-
ListOperations.Head,
102-
ListOperations.Tail,
103-
].includes(operations as ListOperations) && (
182+
{showNum && (
104183
<FormField
105184
control={form.control}
106185
name="n"
107186
render={({ field }) => (
108187
<FormItem>
109-
<FormLabel>{t('flowNum')}</FormLabel>
188+
<FormLabel>{t('flow.flowNum')}</FormLabel>
110189
<FormControl>
111-
<NumberInput {...field} className="w-full"></NumberInput>
190+
<NumberInput
191+
{...field}
192+
className="w-full"
193+
min={1}
194+
></NumberInput>
112195
</FormControl>
113196
<FormMessage />
114197
</FormItem>
115198
)}
116199
/>
117200
)}
118-
{[ListOperations.Sort].includes(operations as ListOperations) && (
201+
{showSortMethod && (
119202
<RAGFlowFormItem name="sort_method" label={t('flow.sortMethod')}>
120203
<SelectWithSearch options={SortMethodOptions} />
121204
</RAGFlowFormItem>
122205
)}
123-
{[ListOperations.Filter].includes(operations as ListOperations) && (
206+
{showFilter && (
124207
<div className="flex items-center gap-2">
125208
<RAGFlowFormItem name="filter.operator" className="flex-1">
126209
<SelectWithSearch options={operatorOptions}></SelectWithSearch>

web/src/pages/agent/form/variable-assigner-form/dynamic-variables.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
VariableAssignerLogicalOperator,
2020
} from '../../constant';
2121
import { useGetVariableLabelOrTypeByValue } from '../../hooks/use-get-begin-query';
22+
import { getArrayElementType } from '../../utils';
2223
import { DynamicFormHeader } from '../components/dynamic-fom-header';
2324
import { QueryVariable } from '../components/query-variable';
2425
import { useBuildLogicalOptions } from './use-build-logical-options';
@@ -152,9 +153,13 @@ export function DynamicVariables({
152153
} else if (
153154
logicalOperator === VariableAssignerLogicalArrayOperator.Append
154155
) {
155-
const subType = type.match(/<([^>]+)>/).at(1);
156+
const subType = getArrayElementType(type);
156157
return (
157-
<QueryVariable types={[subType]} hideLabel pureQuery></QueryVariable>
158+
<QueryVariable
159+
types={[subType as JsonSchemaDataType]}
160+
hideLabel
161+
pureQuery
162+
></QueryVariable>
158163
);
159164
}
160165
},

web/src/pages/agent/gobal-variable-sheet/constant.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { FormFieldConfig, FormFieldType } from '@/components/dynamic-form';
22
import { buildSelectOptions } from '@/utils/component-util';
33
import { t } from 'i18next';
4+
import { TypesWithArray } from '../constant';
5+
export { TypesWithArray } from '../constant';
46
// const TypesWithoutArray = Object.values(JsonSchemaDataType).filter(
57
// (item) => item !== JsonSchemaDataType.Array,
68
// );
@@ -9,17 +11,6 @@ import { t } from 'i18next';
911
// ...TypesWithoutArray.map((item) => `array<${item}>`),
1012
// ];
1113

12-
export enum TypesWithArray {
13-
String = 'string',
14-
Number = 'number',
15-
Boolean = 'boolean',
16-
Object = 'object',
17-
ArrayString = 'array<string>',
18-
ArrayNumber = 'array<number>',
19-
ArrayBoolean = 'array<boolean>',
20-
ArrayObject = 'array<object>',
21-
}
22-
2314
export const GlobalFormFields = [
2415
{
2516
label: t('flow.name'),

web/src/pages/agent/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,3 +732,7 @@ export function buildBeginQueryWithObject(
732732

733733
return nextInputs;
734734
}
735+
736+
export function getArrayElementType(type: string) {
737+
return typeof type === 'string' ? type.match(/<([^>]+)>/)?.at(1) ?? '' : '';
738+
}

0 commit comments

Comments
 (0)