mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Add agent advanced settings form #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -1,5 +1,4 @@
|
||||
import { Form, InputNumber } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
@ -9,7 +8,7 @@ import {
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from './ui/form';
|
||||
import { BlurInput, Input } from './ui/input';
|
||||
import { NumberInput } from './ui/input';
|
||||
|
||||
const MessageHistoryWindowSizeItem = ({
|
||||
initialValue,
|
||||
@ -32,20 +31,10 @@ const MessageHistoryWindowSizeItem = ({
|
||||
|
||||
export default MessageHistoryWindowSizeItem;
|
||||
|
||||
type MessageHistoryWindowSizeFormFieldProps = {
|
||||
useBlurInput?: boolean;
|
||||
};
|
||||
|
||||
export function MessageHistoryWindowSizeFormField({
|
||||
useBlurInput = false,
|
||||
}: MessageHistoryWindowSizeFormFieldProps) {
|
||||
export function MessageHistoryWindowSizeFormField() {
|
||||
const form = useFormContext();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const NextInput = useMemo(() => {
|
||||
return useBlurInput ? BlurInput : Input;
|
||||
}, [useBlurInput]);
|
||||
|
||||
return (
|
||||
<FormField
|
||||
control={form.control}
|
||||
@ -56,7 +45,7 @@ export function MessageHistoryWindowSizeFormField({
|
||||
{t('flow.messageHistoryWindowSize')}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<NextInput {...field} type={'number'}></NextInput>
|
||||
<NumberInput {...field}></NumberInput>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@ -110,3 +110,18 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
export const BlurInput = React.memo(InnerBlurInput);
|
||||
|
||||
export { ExpandedInput, Input, SearchInput };
|
||||
|
||||
type NumberInputProps = { onChange?(value: number): void } & InputProps;
|
||||
|
||||
export const NumberInput = ({ onChange, ...props }: NumberInputProps) => {
|
||||
return (
|
||||
<Input
|
||||
type="number"
|
||||
onChange={(ev) => {
|
||||
const value = ev.target.value;
|
||||
onChange?.(value === '' ? 0 : Number(value)); // convert to number
|
||||
}}
|
||||
{...props}
|
||||
></Input>
|
||||
);
|
||||
};
|
||||
|
||||
@ -81,7 +81,7 @@ const SheetContent = React.forwardRef<
|
||||
</SheetPortal>
|
||||
),
|
||||
);
|
||||
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
||||
SheetContent.displayName = SheetPrimitive.Content.displayName || 'SheetContent';
|
||||
|
||||
const SheetHeader = ({
|
||||
className,
|
||||
|
||||
@ -681,6 +681,13 @@ export const initialAgentValues = {
|
||||
sys_prompt: ``,
|
||||
prompts: [{ role: PromptRole.User, content: `{${AgentGlobals.SysQuery}}` }],
|
||||
message_history_window_size: 12,
|
||||
max_retries: 3,
|
||||
delay_after_error: 1,
|
||||
visual_files_var: '',
|
||||
max_rounds: 5,
|
||||
exception_method: null,
|
||||
exception_comment: '',
|
||||
exception_goto: '',
|
||||
tools: [],
|
||||
outputs: {
|
||||
structured_output: {
|
||||
@ -941,6 +948,7 @@ export enum NodeHandleId {
|
||||
export enum VariableType {
|
||||
String = 'string',
|
||||
Array = 'array',
|
||||
File = 'file',
|
||||
}
|
||||
|
||||
export const DefaultAgentToolValuesMap = {
|
||||
@ -952,3 +960,9 @@ export const DefaultAgentToolValuesMap = {
|
||||
api_key: '',
|
||||
},
|
||||
};
|
||||
|
||||
export enum AgentExceptionMethod {
|
||||
Comment = 'comment',
|
||||
Goto = 'goto',
|
||||
Null = 'null',
|
||||
}
|
||||
|
||||
@ -54,7 +54,10 @@ const FormSheet = ({
|
||||
|
||||
return (
|
||||
<Sheet open={visible} modal={false}>
|
||||
<SheetContent className={cn('top-20 p-0')} closeIcon={false}>
|
||||
<SheetContent
|
||||
className={cn('top-20 p-0 flex flex-col pb-20')}
|
||||
closeIcon={false}
|
||||
>
|
||||
<SheetHeader>
|
||||
<SheetTitle className="hidden"></SheetTitle>
|
||||
<section className="flex-col border-b py-2 px-5">
|
||||
@ -86,7 +89,7 @@ const FormSheet = ({
|
||||
<span>{t(`${lowerFirst(operatorName)}Description`)}</span>
|
||||
</section>
|
||||
</SheetHeader>
|
||||
<section className="pt-4 overflow-auto max-h-[85vh]">
|
||||
<section className="pt-4 overflow-auto flex-1">
|
||||
{visible && (
|
||||
<AgentFormContext.Provider value={node}>
|
||||
<OperatorForm node={node} key={node?.id}></OperatorForm>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { Collapse } from '@/components/collapse';
|
||||
import { FormContainer } from '@/components/form-container';
|
||||
import { LargeModelFormField } from '@/components/large-model-form-field';
|
||||
import { LlmSettingSchema } from '@/components/llm-setting-items/next';
|
||||
@ -9,22 +10,32 @@ import {
|
||||
FormItem,
|
||||
FormLabel,
|
||||
} from '@/components/ui/form';
|
||||
import { Input, NumberInput } from '@/components/ui/input';
|
||||
import { RAGFlowSelect } from '@/components/ui/select';
|
||||
import { buildOptions } from '@/utils/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useMemo } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { z } from 'zod';
|
||||
import { initialAgentValues } from '../../constant';
|
||||
import {
|
||||
AgentExceptionMethod,
|
||||
VariableType,
|
||||
initialAgentValues,
|
||||
} from '../../constant';
|
||||
import { INextOperatorForm } from '../../interface';
|
||||
import useGraphStore from '../../store';
|
||||
import { isBottomSubAgent } from '../../utils';
|
||||
import { DescriptionField } from '../components/description-field';
|
||||
import { Output } from '../components/output';
|
||||
import { PromptEditor } from '../components/prompt-editor';
|
||||
import { QueryVariable } from '../components/query-variable';
|
||||
import { AgentTools, Agents } from './agent-tools';
|
||||
import { useValues } from './use-values';
|
||||
import { useWatchFormChange } from './use-watch-change';
|
||||
|
||||
const exceptionMethodOptions = buildOptions(AgentExceptionMethod);
|
||||
|
||||
const FormSchema = z.object({
|
||||
sys_prompt: z.string(),
|
||||
description: z.string().optional(),
|
||||
@ -46,6 +57,13 @@ const FormSchema = z.object({
|
||||
)
|
||||
.optional(),
|
||||
...LlmSettingSchema,
|
||||
max_retries: z.coerce.number(),
|
||||
delay_after_error: z.coerce.number().optional(),
|
||||
visual_files_var: z.string().optional(),
|
||||
max_rounds: z.coerce.number().optional(),
|
||||
exception_method: z.string().nullable(),
|
||||
exception_comment: z.string().optional(),
|
||||
exception_goto: z.string().optional(),
|
||||
});
|
||||
|
||||
const AgentForm = ({ node }: INextOperatorForm) => {
|
||||
@ -64,7 +82,7 @@ const AgentForm = ({ node }: INextOperatorForm) => {
|
||||
];
|
||||
}, []);
|
||||
|
||||
const form = useForm({
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
defaultValues: defaultValues,
|
||||
resolver: zodResolver(FormSchema),
|
||||
});
|
||||
@ -122,10 +140,87 @@ const AgentForm = ({ node }: INextOperatorForm) => {
|
||||
/>
|
||||
</FormContainer>
|
||||
)}
|
||||
|
||||
<FormContainer>
|
||||
<AgentTools></AgentTools>
|
||||
<Agents node={node}></Agents>
|
||||
</FormContainer>
|
||||
<Collapse title={<div>Advanced Settings</div>}>
|
||||
<FormContainer>
|
||||
<QueryVariable
|
||||
name="visual_files_var"
|
||||
label="Visual files var"
|
||||
></QueryVariable>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`max_retries`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1">
|
||||
<FormLabel>Max retries</FormLabel>
|
||||
<FormControl>
|
||||
<NumberInput {...field} max={8}></NumberInput>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`delay_after_error`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1">
|
||||
<FormLabel>Delay after error</FormLabel>
|
||||
<FormControl>
|
||||
<NumberInput {...field} max={5} step={0.1}></NumberInput>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`max_rounds`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1">
|
||||
<FormLabel>Max rounds</FormLabel>
|
||||
<FormControl>
|
||||
<NumberInput {...field}></NumberInput>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`exception_method`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1">
|
||||
<FormLabel>Exception method</FormLabel>
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
{...field}
|
||||
options={exceptionMethodOptions}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`exception_comment`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1">
|
||||
<FormLabel>Exception comment</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<QueryVariable
|
||||
name="exception_goto"
|
||||
label="Exception goto"
|
||||
type={VariableType.File}
|
||||
></QueryVariable>
|
||||
</FormContainer>
|
||||
</Collapse>
|
||||
<Output list={outputList}></Output>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@ -2,7 +2,7 @@ import { useFetchModelId } from '@/hooks/logic-hooks';
|
||||
import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
||||
import { get, isEmpty } from 'lodash';
|
||||
import { useMemo } from 'react';
|
||||
import { initialAgentValues } from '../../constant';
|
||||
import { AgentExceptionMethod, initialAgentValues } from '../../constant';
|
||||
|
||||
export function useValues(node?: RAGFlowNodeType) {
|
||||
const llmId = useFetchModelId();
|
||||
@ -23,7 +23,14 @@ export function useValues(node?: RAGFlowNodeType) {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
return { ...formData, prompts: get(formData, 'prompts.0.content', '') };
|
||||
return {
|
||||
...formData,
|
||||
prompts: get(formData, 'prompts.0.content', ''),
|
||||
exception_method:
|
||||
formData.exception_method === null
|
||||
? AgentExceptionMethod.Null
|
||||
: formData.exception_method,
|
||||
};
|
||||
}, [defaultValues, node?.data?.form]);
|
||||
|
||||
return values;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { useEffect } from 'react';
|
||||
import { UseFormReturn, useWatch } from 'react-hook-form';
|
||||
import { PromptRole } from '../../constant';
|
||||
import { AgentExceptionMethod, PromptRole } from '../../constant';
|
||||
import useGraphStore from '../../store';
|
||||
|
||||
export function useWatchFormChange(id?: string, form?: UseFormReturn) {
|
||||
export function useWatchFormChange(id?: string, form?: UseFormReturn<any>) {
|
||||
let values = useWatch({ control: form?.control });
|
||||
const updateNodeForm = useGraphStore((state) => state.updateNodeForm);
|
||||
|
||||
@ -14,6 +14,10 @@ export function useWatchFormChange(id?: string, form?: UseFormReturn) {
|
||||
let nextValues: any = {
|
||||
...values,
|
||||
prompts: [{ role: PromptRole.User, content: values.prompts }],
|
||||
exception_method:
|
||||
values.exception_method === AgentExceptionMethod.Null
|
||||
? null
|
||||
: values.exception_method,
|
||||
};
|
||||
|
||||
updateNodeForm(id, nextValues);
|
||||
|
||||
@ -59,9 +59,7 @@ const CategorizeForm = ({ node }: INextOperatorForm) => {
|
||||
<QueryVariable></QueryVariable>
|
||||
<LargeModelFormField></LargeModelFormField>
|
||||
</FormContainer>
|
||||
<MessageHistoryWindowSizeFormField
|
||||
useBlurInput
|
||||
></MessageHistoryWindowSizeFormField>
|
||||
<MessageHistoryWindowSizeFormField></MessageHistoryWindowSizeFormField>
|
||||
<DynamicCategorize nodeId={node?.id}></DynamicCategorize>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@ -4,7 +4,7 @@ import { UseFormReturn, useWatch } from 'react-hook-form';
|
||||
import useGraphStore from '../../store';
|
||||
import { buildCategorizeObjectFromList } from '../../utils';
|
||||
|
||||
export function useWatchFormChange(id?: string, form?: UseFormReturn) {
|
||||
export function useWatchFormChange(id?: string, form?: UseFormReturn<any>) {
|
||||
let values = useWatch({ control: form?.control });
|
||||
const updateNodeForm = useGraphStore((state) => state.updateNodeForm);
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ export function QueryVariable({
|
||||
? nextOptions.map((x) => {
|
||||
return {
|
||||
...x,
|
||||
options: x.options.filter((y) => toLower(y.type).startsWith(type)),
|
||||
options: x.options.filter((y) => toLower(y.type).includes(type)),
|
||||
};
|
||||
})
|
||||
: nextOptions;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { AgentGlobals } from '@/constants/agent';
|
||||
import { useFetchAgent } from '@/hooks/use-agent-request';
|
||||
import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
||||
import { Edge } from '@xyflow/react';
|
||||
@ -161,7 +162,9 @@ export function useBuildQueryVariableOptions() {
|
||||
const globalOptions = Object.entries(globals).map(([key, value]) => ({
|
||||
label: key,
|
||||
value: key,
|
||||
type: Array.isArray(value) ? VariableType.Array : typeof value,
|
||||
type: Array.isArray(value)
|
||||
? `${VariableType.Array}${key === AgentGlobals.SysFiles ? '<file>' : ''}`
|
||||
: typeof value,
|
||||
}));
|
||||
return [
|
||||
{ ...options[0], options: [...options[0]?.options, ...globalOptions] },
|
||||
|
||||
Reference in New Issue
Block a user