### What problem does this PR solve? Feat: Remove the exception comment field from the agent form #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.20.0
| > | > | ||||
| {value ? ( | {value ? ( | ||||
| <span className="flex min-w-0 options-center gap-2"> | <span className="flex min-w-0 options-center gap-2"> | ||||
| <span className="text-lg leading-none truncate"> | |||||
| {selectLabel} | |||||
| </span> | |||||
| <span className="leading-none truncate">{selectLabel}</span> | |||||
| </span> | </span> | ||||
| ) : ( | ) : ( | ||||
| <span className="text-muted-foreground">Select value</span> | <span className="text-muted-foreground">Select value</span> | ||||
| disabled={option.disabled} | disabled={option.disabled} | ||||
| onSelect={handleSelect} | onSelect={handleSelect} | ||||
| > | > | ||||
| <span className="text-lg leading-none"> | |||||
| {option.label} | |||||
| </span> | |||||
| <span className="leading-none">{option.label}</span> | |||||
| {value === option.value && ( | {value === option.value && ( | ||||
| <CheckIcon size={16} className="ml-auto" /> | <CheckIcon size={16} className="ml-auto" /> | ||||
| disabled={group.disabled} | disabled={group.disabled} | ||||
| onSelect={handleSelect} | onSelect={handleSelect} | ||||
| > | > | ||||
| <span className="text-lg leading-none"> | |||||
| {group.label} | |||||
| </span> | |||||
| <span className="leading-none">{group.label}</span> | |||||
| {value === group.value && ( | {value === group.value && ( | ||||
| <CheckIcon size={16} className="ml-auto" /> | <CheckIcon size={16} className="ml-auto" /> |
| file: 'File upload', | file: 'File upload', | ||||
| integer: 'Number', | integer: 'Number', | ||||
| boolean: 'Boolean', | boolean: 'Boolean', | ||||
| goto: 'Fail Branch', | |||||
| comment: 'Default Value', | |||||
| }, | }, | ||||
| llmTools: { | llmTools: { | ||||
| bad_calculator: { | bad_calculator: { |
| import { Handle, NodeProps, Position } from '@xyflow/react'; | import { Handle, NodeProps, Position } from '@xyflow/react'; | ||||
| import { get } from 'lodash'; | import { get } from 'lodash'; | ||||
| import { memo, useMemo } from 'react'; | import { memo, useMemo } from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { AgentExceptionMethod, NodeHandleId } from '../../constant'; | import { AgentExceptionMethod, NodeHandleId } from '../../constant'; | ||||
| import useGraphStore from '../../store'; | import useGraphStore from '../../store'; | ||||
| import { isBottomSubAgent } from '../../utils'; | import { isBottomSubAgent } from '../../utils'; | ||||
| selected, | selected, | ||||
| }: NodeProps<IAgentNode>) { | }: NodeProps<IAgentNode>) { | ||||
| const edges = useGraphStore((state) => state.edges); | const edges = useGraphStore((state) => state.edges); | ||||
| const { t } = useTranslation(); | |||||
| const isHeadAgent = useMemo(() => { | const isHeadAgent = useMemo(() => { | ||||
| return !isBottomSubAgent(edges, id); | return !isBottomSubAgent(edges, id); | ||||
| {(isGotoMethod || | {(isGotoMethod || | ||||
| exceptionMethod === AgentExceptionMethod.Comment) && ( | exceptionMethod === AgentExceptionMethod.Comment) && ( | ||||
| <div className="bg-background-card rounded-sm p-1 flex justify-between gap-2"> | <div className="bg-background-card rounded-sm p-1 flex justify-between gap-2"> | ||||
| <span className="text-text-sub-title">Abnormal</span> | |||||
| <span className="truncate flex-1"> | |||||
| {isGotoMethod ? 'Exception branch' : 'Output default value'} | |||||
| <span className="text-text-sub-title">On Failure</span> | |||||
| <span className="truncate flex-1 text-right"> | |||||
| {t(`flow.${exceptionMethod}`)} | |||||
| </span> | </span> | ||||
| </div> | </div> | ||||
| )} | )} |
| ...initialLlmBaseValues, | ...initialLlmBaseValues, | ||||
| description: '', | description: '', | ||||
| user_prompt: '', | user_prompt: '', | ||||
| sys_prompt: ``, | |||||
| sys_prompt: `<role> | |||||
| You are {{agent_name}}, an AI assistant specialized in {{domain_or_task}}. | |||||
| </role> | |||||
| <instructions> | |||||
| 1. Understand the user’s request. | |||||
| 2. Decompose it into logical subtasks. | |||||
| 3. Execute each subtask step by step, reasoning transparently. | |||||
| 4. Validate accuracy and consistency. | |||||
| 5. Summarize the final result clearly. | |||||
| </instructions>`, | |||||
| prompts: [{ role: PromptRole.User, content: `{${AgentGlobals.SysQuery}}` }], | prompts: [{ role: PromptRole.User, content: `{${AgentGlobals.SysQuery}}` }], | ||||
| message_history_window_size: 12, | message_history_window_size: 12, | ||||
| max_retries: 3, | max_retries: 3, | ||||
| delay_after_error: 1, | delay_after_error: 1, | ||||
| visual_files_var: '', | visual_files_var: '', | ||||
| max_rounds: 5, | max_rounds: 5, | ||||
| exception_method: null, | |||||
| exception_comment: '', | |||||
| exception_method: '', | |||||
| exception_goto: [], | exception_goto: [], | ||||
| exception_default_value: '', | exception_default_value: '', | ||||
| tools: [], | tools: [], | ||||
| export enum AgentExceptionMethod { | export enum AgentExceptionMethod { | ||||
| Comment = 'comment', | Comment = 'comment', | ||||
| Goto = 'goto', | Goto = 'goto', | ||||
| Null = 'null', | |||||
| } | } |
| } from '@/components/large-model-form-field'; | } from '@/components/large-model-form-field'; | ||||
| import { LlmSettingSchema } from '@/components/llm-setting-items/next'; | import { LlmSettingSchema } from '@/components/llm-setting-items/next'; | ||||
| import { MessageHistoryWindowSizeFormField } from '@/components/message-history-window-size-item'; | import { MessageHistoryWindowSizeFormField } from '@/components/message-history-window-size-item'; | ||||
| import { SelectWithSearch } from '@/components/originui/select-with-search'; | |||||
| import { | import { | ||||
| Form, | Form, | ||||
| FormControl, | FormControl, | ||||
| FormLabel, | FormLabel, | ||||
| } from '@/components/ui/form'; | } from '@/components/ui/form'; | ||||
| import { Input, NumberInput } from '@/components/ui/input'; | import { Input, NumberInput } from '@/components/ui/input'; | ||||
| import { RAGFlowSelect } from '@/components/ui/select'; | |||||
| import { LlmModelType } from '@/constants/knowledge'; | import { LlmModelType } from '@/constants/knowledge'; | ||||
| import { useFindLlmByUuid } from '@/hooks/use-llm-request'; | import { useFindLlmByUuid } from '@/hooks/use-llm-request'; | ||||
| import { buildOptions } from '@/utils/form'; | |||||
| import { zodResolver } from '@hookform/resolvers/zod'; | import { zodResolver } from '@hookform/resolvers/zod'; | ||||
| import { memo, useEffect, useMemo } from 'react'; | import { memo, useEffect, useMemo } from 'react'; | ||||
| import { useForm, useWatch } from 'react-hook-form'; | import { useForm, useWatch } from 'react-hook-form'; | ||||
| import { useValues } from './use-values'; | import { useValues } from './use-values'; | ||||
| import { useWatchFormChange } from './use-watch-change'; | import { useWatchFormChange } from './use-watch-change'; | ||||
| const exceptionMethodOptions = buildOptions(AgentExceptionMethod); | |||||
| const FormSchema = z.object({ | const FormSchema = z.object({ | ||||
| sys_prompt: z.string(), | sys_prompt: z.string(), | ||||
| description: z.string().optional(), | description: z.string().optional(), | ||||
| delay_after_error: z.coerce.number().optional(), | delay_after_error: z.coerce.number().optional(), | ||||
| visual_files_var: z.string().optional(), | visual_files_var: z.string().optional(), | ||||
| max_rounds: z.coerce.number().optional(), | max_rounds: z.coerce.number().optional(), | ||||
| exception_method: z.string().nullable(), | |||||
| exception_comment: z.string().optional(), | |||||
| exception_method: z.string().optional(), | |||||
| exception_goto: z.array(z.string()).optional(), | exception_goto: z.array(z.string()).optional(), | ||||
| exception_default_value: z.string().optional(), | exception_default_value: z.string().optional(), | ||||
| ...LargeModelFilterFormSchema, | ...LargeModelFilterFormSchema, | ||||
| const defaultValues = useValues(node); | const defaultValues = useValues(node); | ||||
| const ExceptionMethodOptions = Object.values(AgentExceptionMethod).map( | |||||
| (x) => ({ | |||||
| label: t(`flow.${x}`), | |||||
| value: x, | |||||
| }), | |||||
| ); | |||||
| const isSubAgent = useMemo(() => { | const isSubAgent = useMemo(() => { | ||||
| return isBottomSubAgent(edges, node?.id); | return isBottomSubAgent(edges, node?.id); | ||||
| }, [edges, node?.id]); | }, [edges, node?.id]); | ||||
| <FormItem className="flex-1"> | <FormItem className="flex-1"> | ||||
| <FormLabel>Exception method</FormLabel> | <FormLabel>Exception method</FormLabel> | ||||
| <FormControl> | <FormControl> | ||||
| <RAGFlowSelect | |||||
| <SelectWithSearch | |||||
| {...field} | {...field} | ||||
| options={exceptionMethodOptions} | |||||
| options={ExceptionMethodOptions} | |||||
| allowClear | |||||
| /> | /> | ||||
| </FormControl> | </FormControl> | ||||
| </FormItem> | </FormItem> | ||||
| )} | )} | ||||
| /> | /> | ||||
| <FormField | |||||
| control={form.control} | |||||
| name={`exception_default_value`} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormLabel>Exception default value</FormLabel> | |||||
| <FormControl> | |||||
| <Input {...field} /> | |||||
| </FormControl> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={`exception_comment`} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormLabel>Exception comment</FormLabel> | |||||
| <FormControl> | |||||
| <Input {...field} /> | |||||
| </FormControl> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| {exceptionMethod === AgentExceptionMethod.Comment && ( | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={`exception_default_value`} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormLabel>Exception default value</FormLabel> | |||||
| <FormControl> | |||||
| <Input {...field} /> | |||||
| </FormControl> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| )} | |||||
| </FormContainer> | </FormContainer> | ||||
| </Collapse> | </Collapse> | ||||
| <Output list={outputList}></Output> | <Output list={outputList}></Output> |
| import { RAGFlowNodeType } from '@/interfaces/database/flow'; | import { RAGFlowNodeType } from '@/interfaces/database/flow'; | ||||
| import { get, isEmpty } from 'lodash'; | import { get, isEmpty } from 'lodash'; | ||||
| import { useMemo } from 'react'; | import { useMemo } from 'react'; | ||||
| import { AgentExceptionMethod, initialAgentValues } from '../../constant'; | |||||
| import { initialAgentValues } from '../../constant'; | |||||
| export function useValues(node?: RAGFlowNodeType) { | export function useValues(node?: RAGFlowNodeType) { | ||||
| const llmId = useFetchModelId(); | const llmId = useFetchModelId(); | ||||
| return { | return { | ||||
| ...formData, | ...formData, | ||||
| prompts: get(formData, 'prompts.0.content', ''), | prompts: get(formData, 'prompts.0.content', ''), | ||||
| exception_method: | |||||
| formData.exception_method === null | |||||
| ? AgentExceptionMethod.Null | |||||
| : formData.exception_method, | |||||
| }; | }; | ||||
| }, [defaultValues, node?.data?.form]); | }, [defaultValues, node?.data?.form]); | ||||
| import { useEffect } from 'react'; | import { useEffect } from 'react'; | ||||
| import { UseFormReturn, useWatch } from 'react-hook-form'; | import { UseFormReturn, useWatch } from 'react-hook-form'; | ||||
| import { AgentExceptionMethod, PromptRole } from '../../constant'; | |||||
| import { PromptRole } from '../../constant'; | |||||
| import useGraphStore from '../../store'; | import useGraphStore from '../../store'; | ||||
| export function useWatchFormChange(id?: string, form?: UseFormReturn<any>) { | export function useWatchFormChange(id?: string, form?: UseFormReturn<any>) { | ||||
| let nextValues: any = { | let nextValues: any = { | ||||
| ...values, | ...values, | ||||
| prompts: [{ role: PromptRole.User, content: values.prompts }], | prompts: [{ role: PromptRole.User, content: values.prompts }], | ||||
| exception_method: | |||||
| values.exception_method === AgentExceptionMethod.Null | |||||
| ? null | |||||
| : values.exception_method, | |||||
| }; | }; | ||||
| updateNodeForm(id, nextValues); | updateNodeForm(id, nextValues); |