### What problem does this PR solve? Feat: Verify the parameters of the begin operator #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.19.x
| import * as React from 'react'; | import * as React from 'react'; | ||||
| import { cn } from '@/lib/utils'; | import { cn } from '@/lib/utils'; | ||||
| import { Loader2 } from 'lucide-react'; | |||||
| import { Loader2, Plus } from 'lucide-react'; | |||||
| const buttonVariants = cva( | const buttonVariants = cva( | ||||
| 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', | 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', | ||||
| ButtonLoading.displayName = 'ButtonLoading'; | ButtonLoading.displayName = 'ButtonLoading'; | ||||
| export { Button, buttonVariants }; | export { Button, buttonVariants }; | ||||
| export const BlockButton = React.forwardRef<HTMLButtonElement, ButtonProps>( | |||||
| ({ children, className, ...props }, ref) => { | |||||
| return ( | |||||
| <Button | |||||
| variant={'outline'} | |||||
| ref={ref} | |||||
| className={cn('w-full border-dashed border-input-border', className)} | |||||
| {...props} | |||||
| > | |||||
| <Plus /> {children} | |||||
| </Button> | |||||
| ); | |||||
| }, | |||||
| ); |
| Operator.Switch, | Operator.Switch, | ||||
| Operator.Iteration, | Operator.Iteration, | ||||
| ]; | ]; | ||||
| export enum AgentDialogueMode { | |||||
| Conversational = 'Conversational', | |||||
| Task = 'Task', | |||||
| } |
| import { CodeTemplateStrMap, ProgrammingLanguage } from '@/constants/agent'; | import { CodeTemplateStrMap, ProgrammingLanguage } from '@/constants/agent'; | ||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { z } from 'zod'; | import { z } from 'zod'; | ||||
| import { Operator } from '../constant'; | |||||
| import { AgentDialogueMode, Operator } from '../constant'; | |||||
| import AkShareForm from '../form/akshare-form'; | import AkShareForm from '../form/akshare-form'; | ||||
| import AnswerForm from '../form/answer-form'; | import AnswerForm from '../form/answer-form'; | ||||
| import ArXivForm from '../form/arxiv-form'; | import ArXivForm from '../form/arxiv-form'; | ||||
| [Operator.Begin]: { | [Operator.Begin]: { | ||||
| component: BeginForm, | component: BeginForm, | ||||
| defaultValues: { | defaultValues: { | ||||
| enablePrologue: true, | |||||
| prologue: t('chat.setAnOpenerInitial'), | prologue: t('chat.setAnOpenerInitial'), | ||||
| mode: AgentDialogueMode.Conversational, | |||||
| }, | }, | ||||
| schema: z.object({ | schema: z.object({ | ||||
| enablePrologue: z.boolean(), | |||||
| prologue: z | prologue: z | ||||
| .string() | .string() | ||||
| .min(1, { | .min(1, { | ||||
| message: t('common.namePlaceholder'), | message: t('common.namePlaceholder'), | ||||
| }) | }) | ||||
| .trim(), | .trim(), | ||||
| mode: z.string(), | |||||
| query: z.array( | query: z.array( | ||||
| z.object({ | z.object({ | ||||
| key: z.string(), | key: z.string(), |
| import { Button } from '@/components/ui/button'; | |||||
| import { BlockButton } from '@/components/ui/button'; | |||||
| import { | import { | ||||
| Form, | Form, | ||||
| FormControl, | FormControl, | ||||
| FormLabel, | FormLabel, | ||||
| FormMessage, | FormMessage, | ||||
| } from '@/components/ui/form'; | } from '@/components/ui/form'; | ||||
| import { RAGFlowSelect } from '@/components/ui/select'; | |||||
| import { Switch } from '@/components/ui/switch'; | |||||
| import { Textarea } from '@/components/ui/textarea'; | import { Textarea } from '@/components/ui/textarea'; | ||||
| import { buildSelectOptions } from '@/utils/common-util'; | |||||
| import { useCallback } from 'react'; | import { useCallback } from 'react'; | ||||
| import { useWatch } from 'react-hook-form'; | import { useWatch } from 'react-hook-form'; | ||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { AgentDialogueMode } from '../../constant'; | |||||
| import { BeginQuery, INextOperatorForm } from '../../interface'; | import { BeginQuery, INextOperatorForm } from '../../interface'; | ||||
| import { useEditQueryRecord } from './hooks'; | import { useEditQueryRecord } from './hooks'; | ||||
| import { ParameterDialog } from './next-paramater-modal'; | |||||
| import { ParameterDialog } from './paramater-dialog'; | |||||
| import QueryTable from './query-table'; | import QueryTable from './query-table'; | ||||
| const ModeOptions = buildSelectOptions([ | |||||
| (AgentDialogueMode.Conversational, AgentDialogueMode.Task), | |||||
| ]); | |||||
| const BeginForm = ({ form }: INextOperatorForm) => { | const BeginForm = ({ form }: INextOperatorForm) => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const query = useWatch({ control: form.control, name: 'query' }); | const query = useWatch({ control: form.control, name: 'query' }); | ||||
| const enablePrologue = useWatch({ | |||||
| control: form.control, | |||||
| name: 'enablePrologue', | |||||
| }); | |||||
| const { | const { | ||||
| ok, | ok, | ||||
| ); | ); | ||||
| return ( | return ( | ||||
| <Form {...form}> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'prologue'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel tooltip={t('chat.setAnOpenerTip')}> | |||||
| {t('chat.setAnOpener')} | |||||
| </FormLabel> | |||||
| <FormControl> | |||||
| <Textarea | |||||
| rows={5} | |||||
| {...field} | |||||
| placeholder={t('common.pleaseInput')} | |||||
| ></Textarea> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| <section className="px-5 space-y-5"> | |||||
| <Form {...form}> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'mode'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel tooltip={t('chat.setAnOpenerTip')}>Mode</FormLabel> | |||||
| <FormControl> | |||||
| <RAGFlowSelect | |||||
| placeholder={t('common.pleaseSelect')} | |||||
| options={ModeOptions} | |||||
| {...field} | |||||
| ></RAGFlowSelect> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'enablePrologue'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel tooltip={t('chat.setAnOpenerTip')}> | |||||
| Welcome Message | |||||
| </FormLabel> | |||||
| <FormControl> | |||||
| <Switch | |||||
| checked={field.value} | |||||
| onCheckedChange={field.onChange} | |||||
| /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| {enablePrologue && ( | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'prologue'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel tooltip={t('chat.setAnOpenerTip')}> | |||||
| {t('chat.setAnOpener')} | |||||
| </FormLabel> | |||||
| <FormControl> | |||||
| <Textarea | |||||
| rows={5} | |||||
| {...field} | |||||
| placeholder={t('common.pleaseInput')} | |||||
| ></Textarea> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| )} | )} | ||||
| /> | |||||
| {/* Create a hidden field to make Form instance record this */} | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'query'} | |||||
| render={() => <div></div>} | |||||
| /> | |||||
| <QueryTable | |||||
| data={query} | |||||
| showModal={showModal} | |||||
| deleteRecord={handleDeleteRecord} | |||||
| ></QueryTable> | |||||
| <Button onClick={() => showModal()}>{t('flow.addItem')}</Button> | |||||
| {visible && ( | |||||
| <ParameterDialog | |||||
| visible={visible} | |||||
| hideModal={hideModal} | |||||
| initialValue={currentRecord} | |||||
| onOk={ok} | |||||
| otherThanCurrentQuery={otherThanCurrentQuery} | |||||
| ></ParameterDialog> | |||||
| )} | |||||
| </Form> | |||||
| {/* Create a hidden field to make Form instance record this */} | |||||
| {/* <FormField | |||||
| control={form.control} | |||||
| name={'query'} | |||||
| render={() => <div></div>} | |||||
| /> */} | |||||
| <QueryTable | |||||
| data={query} | |||||
| showModal={showModal} | |||||
| deleteRecord={handleDeleteRecord} | |||||
| ></QueryTable> | |||||
| <BlockButton onClick={() => showModal()}> | |||||
| {t('flow.addItem')} | |||||
| </BlockButton> | |||||
| {visible && ( | |||||
| <ParameterDialog | |||||
| visible={visible} | |||||
| hideModal={hideModal} | |||||
| initialValue={currentRecord} | |||||
| onOk={ok} | |||||
| otherThanCurrentQuery={otherThanCurrentQuery} | |||||
| ></ParameterDialog> | |||||
| )} | |||||
| </Form> | |||||
| </section> | |||||
| ); | ); | ||||
| }; | }; | ||||
| import { toast } from '@/components/hooks/use-toast'; | |||||
| import { Button } from '@/components/ui/button'; | import { Button } from '@/components/ui/button'; | ||||
| import { | import { | ||||
| Dialog, | Dialog, | ||||
| key: z | key: z | ||||
| .string() | .string() | ||||
| .trim() | .trim() | ||||
| .min(1) | |||||
| .refine( | .refine( | ||||
| (value) => | (value) => | ||||
| !value || !otherThanCurrentQuery.some((x) => x.key === value), | !value || !otherThanCurrentQuery.some((x) => x.key === value), | ||||
| { message: 'The key cannot be repeated!' }, | { message: 'The key cannot be repeated!' }, | ||||
| ), | ), | ||||
| optional: z.boolean(), | optional: z.boolean(), | ||||
| options: z.array(z.string().or(z.boolean()).or(z.number())), | |||||
| name: z.string().trim().min(1), | |||||
| options: z.array(z.string().or(z.boolean()).or(z.number())).optional(), | |||||
| }); | }); | ||||
| const form = useForm<z.infer<typeof FormSchema>>({ | const form = useForm<z.infer<typeof FormSchema>>({ | ||||
| defaultValues: { | defaultValues: { | ||||
| type: BeginQueryType.Line, | type: BeginQueryType.Line, | ||||
| optional: false, | optional: false, | ||||
| key: '', | |||||
| name: '', | |||||
| }, | }, | ||||
| }); | }); | ||||
| }, [form, initialValue]); | }, [form, initialValue]); | ||||
| function onSubmit(data: z.infer<typeof FormSchema>) { | function onSubmit(data: z.infer<typeof FormSchema>) { | ||||
| toast({ | |||||
| title: 'You submitted the following values:', | |||||
| description: ( | |||||
| <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4"> | |||||
| <code className="text-white">{JSON.stringify(data, null, 2)}</code> | |||||
| </pre> | |||||
| ), | |||||
| }); | |||||
| console.log('🚀 ~ onSubmit ~ data:', data); | |||||
| } | } | ||||
| return ( | return ( | ||||
| <Form {...form}> | <Form {...form}> | ||||
| <form onSubmit={form.handleSubmit(onSubmit)} id={FormId}> | |||||
| <form | |||||
| onSubmit={form.handleSubmit(onSubmit)} | |||||
| id={FormId} | |||||
| className="space-y-5" | |||||
| autoComplete="off" | |||||
| > | |||||
| <FormField | <FormField | ||||
| name="type" | name="type" | ||||
| control={form.control} | control={form.control} | ||||
| render={({ field }) => ( | render={({ field }) => ( | ||||
| <FormItem> | <FormItem> | ||||
| <FormLabel>Key</FormLabel> | <FormLabel>Key</FormLabel> | ||||
| <FormControl> | |||||
| <Input {...field} autoComplete="off" /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| name="name" | |||||
| control={form.control} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>Name</FormLabel> | |||||
| <FormControl> | <FormControl> | ||||
| <Input {...field} /> | <Input {...field} /> | ||||
| </FormControl> | </FormControl> | ||||
| initialValue={initialValue} | initialValue={initialValue} | ||||
| otherThanCurrentQuery={otherThanCurrentQuery} | otherThanCurrentQuery={otherThanCurrentQuery} | ||||
| ></ParameterForm> | ></ParameterForm> | ||||
| <DialogFooter> | |||||
| <Button type="submit" form={FormId}> | |||||
| Confirm | |||||
| </Button> | |||||
| </DialogFooter> | |||||
| </DialogContent> | </DialogContent> | ||||
| <DialogFooter> | |||||
| <Button type="submit" id={FormId}> | |||||
| Confirm | |||||
| </Button> | |||||
| </DialogFooter> | |||||
| </Dialog> | </Dialog> | ||||
| ); | ); | ||||
| } | } |
| return nextBytes.toFixed(dp) + ' ' + units[u]; | return nextBytes.toFixed(dp) + ' ' + units[u]; | ||||
| } | } | ||||
| export function buildSelectOptions(list: Array<string>) { | |||||
| return list.map((x) => ({ label: x, value: x })); | |||||
| } |
| 'background-card': 'var(--background-card)', | 'background-card': 'var(--background-card)', | ||||
| 'background-checked': 'var(--background-checked)', | 'background-checked': 'var(--background-checked)', | ||||
| 'input-border': 'var(--input-border)', | |||||
| primary: { | primary: { | ||||
| DEFAULT: 'hsl(var(--primary))', | DEFAULT: 'hsl(var(--primary))', | ||||
| foreground: 'hsl(var(--primary-foreground))', | foreground: 'hsl(var(--primary-foreground))', |
| --background-card: rgba(22, 22, 24, 0.05); | --background-card: rgba(22, 22, 24, 0.05); | ||||
| --background-checked: rgba(76, 164, 231, 1); | --background-checked: rgba(76, 164, 231, 1); | ||||
| --input-border: rgba(22, 22, 24, 0.2); | |||||
| } | } | ||||
| .dark { | .dark { | ||||
| --background-card: rgba(255, 255, 255, 0.05); | --background-card: rgba(255, 255, 255, 0.05); | ||||
| --background-checked: rgba(76, 164, 231, 1); | --background-checked: rgba(76, 164, 231, 1); | ||||
| --input-border: rgba(255, 255, 255, 0.2); | |||||
| } | } | ||||
| } | } | ||||