### What problem does this PR solve? Feat: Migrate the code operator to the new agent. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.19.x
| @@ -27,6 +27,7 @@ import { ReactComponent as TemplateIcon } from '@/assets/svg/template.svg'; | |||
| import { ReactComponent as TuShareIcon } from '@/assets/svg/tushare.svg'; | |||
| import { ReactComponent as WenCaiIcon } from '@/assets/svg/wencai.svg'; | |||
| import { ReactComponent as YahooFinanceIcon } from '@/assets/svg/yahoo-finance.svg'; | |||
| import { CodeTemplateStrMap, ProgrammingLanguage } from '@/constants/agent'; | |||
| // 邮件功能 | |||
| @@ -56,6 +57,7 @@ import upperFirst from 'lodash/upperFirst'; | |||
| import { | |||
| CirclePower, | |||
| CloudUpload, | |||
| CodeXml, | |||
| IterationCcw, | |||
| ListOrdered, | |||
| OptionIcon, | |||
| @@ -103,6 +105,7 @@ export enum Operator { | |||
| Email = 'Email', | |||
| Iteration = 'Iteration', | |||
| IterationStart = 'IterationItem', | |||
| Code = 'Code', | |||
| } | |||
| export const CommonOperatorList = Object.values(Operator).filter( | |||
| @@ -161,6 +164,7 @@ export const operatorIconMap = { | |||
| [Operator.Email]: EmailIcon, | |||
| [Operator.Iteration]: IterationCcw, | |||
| [Operator.IterationStart]: CirclePower, | |||
| [Operator.Code]: CodeXml, | |||
| }; | |||
| export const operatorMap: Record< | |||
| @@ -299,6 +303,7 @@ export const operatorMap: Record< | |||
| [Operator.Email]: { backgroundColor: '#e6f7ff' }, | |||
| [Operator.Iteration]: { backgroundColor: '#e6f7ff' }, | |||
| [Operator.IterationStart]: { backgroundColor: '#e6f7ff' }, | |||
| [Operator.Code]: { backgroundColor: '#4c5458' }, | |||
| }; | |||
| export const componentMenuList = [ | |||
| @@ -336,6 +341,9 @@ export const componentMenuList = [ | |||
| { | |||
| name: Operator.Iteration, | |||
| }, | |||
| { | |||
| name: Operator.Code, | |||
| }, | |||
| { | |||
| name: Operator.Note, | |||
| }, | |||
| @@ -645,6 +653,19 @@ export const initialIterationValues = { | |||
| }; | |||
| export const initialIterationStartValues = {}; | |||
| export const initialCodeValues = { | |||
| lang: 'python', | |||
| script: CodeTemplateStrMap[ProgrammingLanguage.Python], | |||
| arguments: [ | |||
| { | |||
| name: 'arg1', | |||
| }, | |||
| { | |||
| name: 'arg2', | |||
| }, | |||
| ], | |||
| }; | |||
| export const CategorizeAnchorPointPositions = [ | |||
| { top: 1, right: 34 }, | |||
| { top: 8, right: 18 }, | |||
| @@ -726,6 +747,7 @@ export const RestrictedUpstreamMap = { | |||
| [Operator.Email]: [Operator.Begin], | |||
| [Operator.Iteration]: [Operator.Begin], | |||
| [Operator.IterationStart]: [Operator.Begin], | |||
| [Operator.Code]: [Operator.Begin], | |||
| }; | |||
| export const NodeMap = { | |||
| @@ -765,6 +787,7 @@ export const NodeMap = { | |||
| [Operator.Email]: 'emailNode', | |||
| [Operator.Iteration]: 'group', | |||
| [Operator.IterationStart]: 'iterationStartNode', | |||
| [Operator.Code]: 'ragNode', | |||
| }; | |||
| export const LanguageOptions = [ | |||
| @@ -98,7 +98,7 @@ const FormSheet = ({ | |||
| return ( | |||
| <Sheet open={visible} modal={false}> | |||
| <SheetTitle className="hidden"></SheetTitle> | |||
| <SheetContent className={cn('bg-white top-20 p-0')} closeIcon={false}> | |||
| <SheetContent className={cn('top-20 p-0')} closeIcon={false}> | |||
| <SheetHeader> | |||
| <section className="flex-col border-b py-2 px-5"> | |||
| <div className="flex items-center gap-2 pb-3"> | |||
| @@ -9,6 +9,7 @@ import BaiduForm from '../form/baidu-form'; | |||
| import BeginForm from '../form/begin-form'; | |||
| import BingForm from '../form/bing-form'; | |||
| import CategorizeForm from '../form/categorize-form'; | |||
| import CodeForm from '../form/code-form'; | |||
| import CrawlerForm from '../form/crawler-form'; | |||
| import DeepLForm from '../form/deepl-form'; | |||
| import DuckDuckGoForm from '../form/duckduckgo-form'; | |||
| @@ -130,6 +131,17 @@ export function useFormConfigMap() { | |||
| language: z.string(), | |||
| }), | |||
| }, | |||
| [Operator.Code]: { | |||
| component: CodeForm, | |||
| defaultValues: { | |||
| message_history_window_size: 6, | |||
| }, | |||
| schema: z.object({ | |||
| llm_id: z.string(), | |||
| message_history_window_size: z.number(), | |||
| language: z.string(), | |||
| }), | |||
| }, | |||
| [Operator.Baidu]: { | |||
| component: BaiduForm, | |||
| defaultValues: { top_n: 10 }, | |||
| @@ -0,0 +1,66 @@ | |||
| import { RAGFlowNodeType } from '@/interfaces/database/flow'; | |||
| import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; | |||
| import { Button, Form, Input, Select } from 'antd'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query'; | |||
| import { FormCollapse } from '../components/dynamic-input-variable'; | |||
| type DynamicInputVariableProps = { | |||
| name?: string; | |||
| node?: RAGFlowNodeType; | |||
| }; | |||
| export const DynamicInputVariable = ({ | |||
| name = 'arguments', | |||
| node, | |||
| }: DynamicInputVariableProps) => { | |||
| const { t } = useTranslation(); | |||
| const valueOptions = useBuildComponentIdSelectOptions( | |||
| node?.id, | |||
| node?.parentId, | |||
| ); | |||
| return ( | |||
| <FormCollapse title={t('flow.inputVariables')}> | |||
| <Form.List name={name}> | |||
| {(fields, { add, remove }) => ( | |||
| <> | |||
| {fields.map(({ key, name, ...restField }) => ( | |||
| <div key={key} className="flex items-center gap-2 pb-4"> | |||
| <Form.Item | |||
| {...restField} | |||
| name={[name, 'name']} | |||
| className="m-0 flex-1" | |||
| > | |||
| <Input /> | |||
| </Form.Item> | |||
| <Form.Item | |||
| {...restField} | |||
| name={[name, 'component_id']} | |||
| className="m-0 flex-1" | |||
| > | |||
| <Select | |||
| placeholder={t('common.pleaseSelect')} | |||
| options={valueOptions} | |||
| ></Select> | |||
| </Form.Item> | |||
| <MinusCircleOutlined onClick={() => remove(name)} /> | |||
| </div> | |||
| ))} | |||
| <Form.Item> | |||
| <Button | |||
| type="dashed" | |||
| onClick={() => add()} | |||
| block | |||
| icon={<PlusOutlined />} | |||
| > | |||
| {t('flow.addVariable')} | |||
| </Button> | |||
| </Form.Item> | |||
| </> | |||
| )} | |||
| </Form.List> | |||
| </FormCollapse> | |||
| ); | |||
| }; | |||
| @@ -0,0 +1,84 @@ | |||
| import Editor, { loader } from '@monaco-editor/react'; | |||
| import { INextOperatorForm } from '../../interface'; | |||
| import { DynamicInputVariable } from './dynamic-input-variable'; | |||
| import { | |||
| Form, | |||
| FormControl, | |||
| FormField, | |||
| FormItem, | |||
| FormLabel, | |||
| FormMessage, | |||
| } from '@/components/ui/form'; | |||
| import { RAGFlowSelect } from '@/components/ui/select'; | |||
| import { ProgrammingLanguage } from '@/constants/agent'; | |||
| import { ICodeForm } from '@/interfaces/database/flow'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| loader.config({ paths: { vs: '/vs' } }); | |||
| const options = [ | |||
| ProgrammingLanguage.Python, | |||
| ProgrammingLanguage.Javascript, | |||
| ].map((x) => ({ value: x, label: x })); | |||
| const CodeForm = ({ form, node }: INextOperatorForm) => { | |||
| const formData = node?.data.form as ICodeForm; | |||
| const { t } = useTranslation(); | |||
| // useEffect(() => { | |||
| // setTimeout(() => { | |||
| // // TODO: Direct operation zustand is more elegant | |||
| // form?.setFieldValue( | |||
| // 'script', | |||
| // CodeTemplateStrMap[formData.lang as ProgrammingLanguage], | |||
| // ); | |||
| // }, 0); | |||
| // }, [form, formData.lang]); | |||
| return ( | |||
| <Form {...form}> | |||
| <DynamicInputVariable node={node}></DynamicInputVariable> | |||
| <FormField | |||
| control={form.control} | |||
| name="script" | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| <FormLabel> | |||
| <FormField | |||
| control={form.control} | |||
| name="channel" | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| <FormLabel tooltip={t('channelTip')}> | |||
| {t('channel')} | |||
| </FormLabel> | |||
| <FormControl> | |||
| <RAGFlowSelect {...field} options={options} /> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| </FormLabel> | |||
| <FormControl> | |||
| <Editor | |||
| height={600} | |||
| theme="vs-dark" | |||
| language={formData.lang} | |||
| options={{ | |||
| minimap: { enabled: false }, | |||
| automaticLayout: true, | |||
| }} | |||
| {...field} | |||
| /> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| </Form> | |||
| ); | |||
| }; | |||
| export default CodeForm; | |||
| @@ -40,6 +40,7 @@ import { | |||
| initialBeginValues, | |||
| initialBingValues, | |||
| initialCategorizeValues, | |||
| initialCodeValues, | |||
| initialConcentratorValues, | |||
| initialCrawlerValues, | |||
| initialDeepLValues, | |||
| @@ -141,6 +142,7 @@ export const useInitializeOperatorParams = () => { | |||
| [Operator.Email]: initialEmailValues, | |||
| [Operator.Iteration]: initialIterationValues, | |||
| [Operator.IterationStart]: initialIterationValues, | |||
| [Operator.Code]: initialCodeValues, | |||
| }; | |||
| }, [llmId]); | |||