### What problem does this PR solve? Feat: Add Email and DuckDuckGo and Wikipedia Operator #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.20.0
| @@ -41,7 +41,6 @@ import { RagNode } from './node'; | |||
| import { AgentNode } from './node/agent-node'; | |||
| import { BeginNode } from './node/begin-node'; | |||
| import { CategorizeNode } from './node/categorize-node'; | |||
| import { EmailNode } from './node/email-node'; | |||
| import { GenerateNode } from './node/generate-node'; | |||
| import { InvokeNode } from './node/invoke-node'; | |||
| import { IterationNode, IterationStartNode } from './node/iteration-node'; | |||
| @@ -71,7 +70,7 @@ export const nodeTypes: NodeTypes = { | |||
| keywordNode: KeywordNode, | |||
| invokeNode: InvokeNode, | |||
| templateNode: TemplateNode, | |||
| emailNode: EmailNode, | |||
| // emailNode: EmailNode, | |||
| group: IterationNode, | |||
| iterationStartNode: IterationStartNode, | |||
| agentNode: AgentNode, | |||
| @@ -104,6 +104,9 @@ function AccordionOperators() { | |||
| Operator.ExeSQL, | |||
| Operator.Google, | |||
| Operator.YahooFinance, | |||
| Operator.Email, | |||
| Operator.DuckDuckGo, | |||
| Operator.Wikipedia, | |||
| ]} | |||
| ></OperatorItemList> | |||
| </AccordionContent> | |||
| @@ -341,7 +341,17 @@ export const initialKeywordExtractValues = { | |||
| export const initialDuckValues = { | |||
| top_n: 10, | |||
| channel: Channel.Text, | |||
| ...initialQueryBaseValues, | |||
| query: AgentGlobals.SysQuery, | |||
| outputs: { | |||
| formalized_content: { | |||
| value: '', | |||
| type: 'string', | |||
| }, | |||
| json: { | |||
| value: [], | |||
| type: 'Array<Object>', | |||
| }, | |||
| }, | |||
| }; | |||
| export const initialBaiduValues = { | |||
| @@ -352,7 +362,13 @@ export const initialBaiduValues = { | |||
| export const initialWikipediaValues = { | |||
| top_n: 10, | |||
| language: 'en', | |||
| ...initialQueryBaseValues, | |||
| query: AgentGlobals.SysQuery, | |||
| outputs: { | |||
| formalized_content: { | |||
| value: '', | |||
| type: 'string', | |||
| }, | |||
| }, | |||
| }; | |||
| export const initialPubMedValues = { | |||
| @@ -526,7 +542,7 @@ export const initialTemplateValues = { | |||
| export const initialEmailValues = { | |||
| smtp_server: '', | |||
| smtp_port: 587, | |||
| smtp_port: 465, | |||
| email: '', | |||
| password: '', | |||
| sender_name: '', | |||
| @@ -534,6 +550,12 @@ export const initialEmailValues = { | |||
| cc_email: '', | |||
| subject: '', | |||
| content: '', | |||
| outputs: { | |||
| success: { | |||
| value: true, | |||
| type: 'boolean', | |||
| }, | |||
| }, | |||
| }; | |||
| export const initialIterationValues = { | |||
| @@ -815,7 +837,7 @@ export const NodeMap = { | |||
| [Operator.Crawler]: 'ragNode', | |||
| [Operator.Invoke]: 'invokeNode', | |||
| [Operator.Template]: 'templateNode', | |||
| [Operator.Email]: 'emailNode', | |||
| [Operator.Email]: 'ragNode', | |||
| [Operator.Iteration]: 'group', | |||
| [Operator.IterationStart]: 'iterationStartNode', | |||
| [Operator.Code]: 'ragNode', | |||
| @@ -1,3 +1,4 @@ | |||
| import { FormContainer } from '@/components/form-container'; | |||
| import { TopNFormField } from '@/components/top-n-item'; | |||
| import { | |||
| Form, | |||
| @@ -9,44 +10,79 @@ import { | |||
| } from '@/components/ui/form'; | |||
| import { RAGFlowSelect } from '@/components/ui/select'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { useMemo } from 'react'; | |||
| import { Channel } from '../../constant'; | |||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||
| import { memo, useMemo } from 'react'; | |||
| import { useForm, useFormContext } from 'react-hook-form'; | |||
| import { z } from 'zod'; | |||
| import { Channel, initialDuckValues } from '../../constant'; | |||
| import { useFormValues } from '../../hooks/use-form-values'; | |||
| import { INextOperatorForm } from '../../interface'; | |||
| import { DynamicInputVariable } from '../components/next-dynamic-input-variable'; | |||
| import { buildOutputList } from '../../utils/build-output-list'; | |||
| import { FormWrapper } from '../components/form-wrapper'; | |||
| import { Output } from '../components/output'; | |||
| import { QueryVariable } from '../components/query-variable'; | |||
| const DuckDuckGoForm = ({ form, node }: INextOperatorForm) => { | |||
| export const DuckDuckGoFormPartialSchema = { | |||
| top_n: z.string(), | |||
| channel: z.string(), | |||
| }; | |||
| const FormSchema = z.object({ | |||
| query: z.string(), | |||
| ...DuckDuckGoFormPartialSchema, | |||
| }); | |||
| export function DuckDuckGoWidgets() { | |||
| const { t } = useTranslate('flow'); | |||
| const form = useFormContext(); | |||
| const options = useMemo(() => { | |||
| return Object.values(Channel).map((x) => ({ value: x, label: t(x) })); | |||
| }, [t]); | |||
| return ( | |||
| <> | |||
| <TopNFormField></TopNFormField> | |||
| <FormField | |||
| control={form.control} | |||
| name={'channel'} | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| <FormLabel tooltip={t('channelTip')}>{t('channel')}</FormLabel> | |||
| <FormControl> | |||
| <RAGFlowSelect {...field} options={options} /> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| </> | |||
| ); | |||
| } | |||
| const outputList = buildOutputList(initialDuckValues.outputs); | |||
| function DuckDuckGoForm({ node }: INextOperatorForm) { | |||
| const defaultValues = useFormValues(initialDuckValues, node); | |||
| const form = useForm<z.infer<typeof FormSchema>>({ | |||
| defaultValues, | |||
| resolver: zodResolver(FormSchema), | |||
| }); | |||
| return ( | |||
| <Form {...form}> | |||
| <form | |||
| className="space-y-6" | |||
| onSubmit={(e) => { | |||
| e.preventDefault(); | |||
| }} | |||
| > | |||
| <DynamicInputVariable node={node}></DynamicInputVariable> | |||
| <TopNFormField></TopNFormField> | |||
| <FormField | |||
| control={form.control} | |||
| name="channel" | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| <FormLabel tooltip={t('channelTip')}>{t('channel')}</FormLabel> | |||
| <FormControl> | |||
| <RAGFlowSelect {...field} options={options} /> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| </form> | |||
| <FormWrapper> | |||
| <FormContainer> | |||
| <QueryVariable></QueryVariable> | |||
| <DuckDuckGoWidgets></DuckDuckGoWidgets> | |||
| </FormContainer> | |||
| </FormWrapper> | |||
| <div className="p-5"> | |||
| <Output list={outputList}></Output> | |||
| </div> | |||
| </Form> | |||
| ); | |||
| }; | |||
| } | |||
| export default DuckDuckGoForm; | |||
| export default memo(DuckDuckGoForm); | |||
| @@ -1,50 +1,119 @@ | |||
| import { FormContainer } from '@/components/form-container'; | |||
| import { | |||
| Form, | |||
| FormControl, | |||
| FormField, | |||
| FormItem, | |||
| FormLabel, | |||
| FormMessage, | |||
| } from '@/components/ui/form'; | |||
| import { Input } from '@/components/ui/input'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { Form, Input } from 'antd'; | |||
| import { IOperatorForm } from '../../interface'; | |||
| import DynamicInputVariable from '../components/dynamic-input-variable'; | |||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||
| import { ReactNode } from 'react'; | |||
| import { useForm, useFormContext } from 'react-hook-form'; | |||
| import { z } from 'zod'; | |||
| import { initialEmailValues } from '../../constant'; | |||
| import { useFormValues } from '../../hooks/use-form-values'; | |||
| import { INextOperatorForm } from '../../interface'; | |||
| import { buildOutputList } from '../../utils/build-output-list'; | |||
| import { FormWrapper } from '../components/form-wrapper'; | |||
| import { Output } from '../components/output'; | |||
| const EmailForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |||
| interface InputFormFieldProps { | |||
| name: string; | |||
| label: ReactNode; | |||
| type?: string; | |||
| } | |||
| function InputFormField({ name, label, type }: InputFormFieldProps) { | |||
| const form = useFormContext(); | |||
| return ( | |||
| <FormField | |||
| control={form.control} | |||
| name={name} | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| <FormLabel>{label}</FormLabel> | |||
| <FormControl> | |||
| <Input {...field} type={type}></Input> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| ); | |||
| } | |||
| export function EmailFormWidgets() { | |||
| const { t } = useTranslate('flow'); | |||
| return ( | |||
| <Form | |||
| name="basic" | |||
| autoComplete="off" | |||
| form={form} | |||
| onValuesChange={onValuesChange} | |||
| layout={'vertical'} | |||
| > | |||
| <DynamicInputVariable node={node}></DynamicInputVariable> | |||
| {/* SMTP服务器配置 */} | |||
| <Form.Item label={t('smtpServer')} name={'smtp_server'}> | |||
| <Input placeholder="smtp.example.com" /> | |||
| </Form.Item> | |||
| <Form.Item label={t('smtpPort')} name={'smtp_port'}> | |||
| <Input type="number" placeholder="587" /> | |||
| </Form.Item> | |||
| <Form.Item label={t('senderEmail')} name={'email'}> | |||
| <Input placeholder="sender@example.com" /> | |||
| </Form.Item> | |||
| <Form.Item label={t('authCode')} name={'password'}> | |||
| <Input.Password placeholder="your_password" /> | |||
| </Form.Item> | |||
| <Form.Item label={t('senderName')} name={'sender_name'}> | |||
| <Input placeholder="Sender Name" /> | |||
| </Form.Item> | |||
| {/* 动态参数说明 */} | |||
| <div style={{ marginBottom: 24 }}> | |||
| <h4>{t('dynamicParameters')}</h4> | |||
| <div>{t('jsonFormatTip')}</div> | |||
| <pre style={{ background: '#f5f5f5', padding: 12, borderRadius: 4 }}> | |||
| {`{ | |||
| "to_email": "recipient@example.com", | |||
| "cc_email": "cc@example.com", | |||
| "subject": "Email Subject", | |||
| "content": "Email Content" | |||
| }`} | |||
| </pre> | |||
| <> | |||
| <InputFormField | |||
| name="smtp_server" | |||
| label={t('smtpServer')} | |||
| ></InputFormField> | |||
| <InputFormField | |||
| name="smtp_port" | |||
| label={t('smtpPort')} | |||
| type="number" | |||
| ></InputFormField> | |||
| <InputFormField name="email" label={t('senderEmail')}></InputFormField> | |||
| <InputFormField | |||
| name="password" | |||
| label={t('authCode')} | |||
| type="password" | |||
| ></InputFormField> | |||
| <InputFormField | |||
| name="sender_name" | |||
| label={t('senderName')} | |||
| ></InputFormField> | |||
| </> | |||
| ); | |||
| } | |||
| export const EmailFormPartialSchema = { | |||
| smtp_server: z.string(), | |||
| smtp_port: z.number(), | |||
| email: z.string(), | |||
| password: z.string(), | |||
| sender_name: z.string(), | |||
| }; | |||
| const FormSchema = z.object({ | |||
| to_email: z.string(), | |||
| cc_email: z.string(), | |||
| content: z.string(), | |||
| subject: z.string(), | |||
| ...EmailFormPartialSchema, | |||
| }); | |||
| const outputList = buildOutputList(initialEmailValues.outputs); | |||
| const EmailForm = ({ node }: INextOperatorForm) => { | |||
| const { t } = useTranslate('flow'); | |||
| const defaultValues = useFormValues(initialEmailValues, node); | |||
| const form = useForm<z.infer<typeof FormSchema>>({ | |||
| defaultValues, | |||
| resolver: zodResolver(FormSchema), | |||
| }); | |||
| return ( | |||
| <Form {...form}> | |||
| <FormWrapper> | |||
| <FormContainer> | |||
| <InputFormField name="to_email" label={t('toEmail')}></InputFormField> | |||
| <InputFormField name="cc_email" label={t('ccEmail')}></InputFormField> | |||
| <InputFormField name="content" label={t('content')}></InputFormField> | |||
| <InputFormField name="subject" label={t('subject')}></InputFormField> | |||
| <EmailFormWidgets></EmailFormWidgets> | |||
| </FormContainer> | |||
| </FormWrapper> | |||
| <div className="p-5"> | |||
| <Output list={outputList}></Output> | |||
| </div> | |||
| </Form> | |||
| ); | |||
| @@ -2,17 +2,17 @@ import { Operator } from '../../constant'; | |||
| import AkShareForm from '../akshare-form'; | |||
| import ArXivForm from '../arxiv-form'; | |||
| import DeepLForm from '../deepl-form'; | |||
| import DuckDuckGoForm from '../duckduckgo-form'; | |||
| import EmailForm from '../email-form'; | |||
| import GithubForm from '../github-form'; | |||
| import GoogleScholarForm from '../google-scholar-form'; | |||
| import PubMedForm from '../pubmed-form'; | |||
| import WikipediaForm from '../wikipedia-form'; | |||
| import BingForm from './bing-form'; | |||
| import CrawlerForm from './crawler-form'; | |||
| import DuckDuckGoForm from './duckduckgo-form'; | |||
| import EmailForm from './email-form'; | |||
| import ExeSQLForm from './exesql-form'; | |||
| import RetrievalForm from './retrieval-form'; | |||
| import TavilyForm from './tavily-form'; | |||
| import WikipediaForm from './wikipedia-form'; | |||
| import YahooFinanceForm from './yahoo-finance-form'; | |||
| export const ToolFormConfigMap = { | |||
| @@ -0,0 +1,38 @@ | |||
| import { FormContainer } from '@/components/form-container'; | |||
| import { Form } from '@/components/ui/form'; | |||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||
| import { memo } from 'react'; | |||
| import { useForm } from 'react-hook-form'; | |||
| import { z } from 'zod'; | |||
| import { FormWrapper } from '../../components/form-wrapper'; | |||
| import { | |||
| DuckDuckGoFormPartialSchema, | |||
| DuckDuckGoWidgets, | |||
| } from '../../duckduckgo-form'; | |||
| import { useValues } from '../use-values'; | |||
| import { useWatchFormChange } from '../use-watch-change'; | |||
| function DuckDuckGoForm() { | |||
| const values = useValues(); | |||
| const FormSchema = z.object(DuckDuckGoFormPartialSchema); | |||
| const form = useForm<z.infer<typeof FormSchema>>({ | |||
| defaultValues: values, | |||
| resolver: zodResolver(FormSchema), | |||
| }); | |||
| useWatchFormChange(form); | |||
| return ( | |||
| <Form {...form}> | |||
| <FormWrapper> | |||
| <FormContainer> | |||
| <DuckDuckGoWidgets></DuckDuckGoWidgets> | |||
| </FormContainer> | |||
| </FormWrapper> | |||
| </Form> | |||
| ); | |||
| } | |||
| export default memo(DuckDuckGoForm); | |||
| @@ -0,0 +1,35 @@ | |||
| import { FormContainer } from '@/components/form-container'; | |||
| import { Form } from '@/components/ui/form'; | |||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||
| import { memo } from 'react'; | |||
| import { useForm } from 'react-hook-form'; | |||
| import { z } from 'zod'; | |||
| import { FormWrapper } from '../../components/form-wrapper'; | |||
| import { EmailFormPartialSchema, EmailFormWidgets } from '../../email-form'; | |||
| import { useValues } from '../use-values'; | |||
| import { useWatchFormChange } from '../use-watch-change'; | |||
| function EmailForm() { | |||
| const values = useValues(); | |||
| const FormSchema = z.object(EmailFormPartialSchema); | |||
| const form = useForm<z.infer<typeof FormSchema>>({ | |||
| defaultValues: values, | |||
| resolver: zodResolver(FormSchema), | |||
| }); | |||
| useWatchFormChange(form); | |||
| return ( | |||
| <Form {...form}> | |||
| <FormWrapper> | |||
| <FormContainer> | |||
| <EmailFormWidgets></EmailFormWidgets> | |||
| </FormContainer> | |||
| </FormWrapper> | |||
| </Form> | |||
| ); | |||
| } | |||
| export default memo(EmailForm); | |||
| @@ -1,6 +1,7 @@ | |||
| import { FormContainer } from '@/components/form-container'; | |||
| import { Form } from '@/components/ui/form'; | |||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||
| import { memo } from 'react'; | |||
| import { useForm } from 'react-hook-form'; | |||
| import { z } from 'zod'; | |||
| import { ApiKeyField } from '../../components/api-key-field'; | |||
| @@ -9,7 +10,7 @@ import { TavilyFormSchema } from '../../tavily-form'; | |||
| import { useValues } from '../use-values'; | |||
| import { useWatchFormChange } from '../use-watch-change'; | |||
| const TavilyForm = () => { | |||
| function TavilyForm() { | |||
| const values = useValues(); | |||
| const FormSchema = z.object(TavilyFormSchema); | |||
| @@ -30,6 +31,6 @@ const TavilyForm = () => { | |||
| </FormWrapper> | |||
| </Form> | |||
| ); | |||
| }; | |||
| } | |||
| export default TavilyForm; | |||
| export default memo(TavilyForm); | |||
| @@ -0,0 +1,38 @@ | |||
| import { FormContainer } from '@/components/form-container'; | |||
| import { Form } from '@/components/ui/form'; | |||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||
| import { memo } from 'react'; | |||
| import { useForm } from 'react-hook-form'; | |||
| import { z } from 'zod'; | |||
| import { FormWrapper } from '../../components/form-wrapper'; | |||
| import { | |||
| WikipediaFormPartialSchema, | |||
| WikipediaFormWidgets, | |||
| } from '../../wikipedia-form'; | |||
| import { useValues } from '../use-values'; | |||
| import { useWatchFormChange } from '../use-watch-change'; | |||
| function WikipediaForm() { | |||
| const values = useValues(); | |||
| const FormSchema = z.object(WikipediaFormPartialSchema); | |||
| const form = useForm<z.infer<typeof FormSchema>>({ | |||
| defaultValues: values, | |||
| resolver: zodResolver(FormSchema), | |||
| }); | |||
| useWatchFormChange(form); | |||
| return ( | |||
| <Form {...form}> | |||
| <FormWrapper> | |||
| <FormContainer> | |||
| <WikipediaFormWidgets></WikipediaFormWidgets> | |||
| </FormContainer> | |||
| </FormWrapper> | |||
| </Form> | |||
| ); | |||
| } | |||
| export default memo(WikipediaForm); | |||
| @@ -1,3 +1,5 @@ | |||
| import { FormContainer } from '@/components/form-container'; | |||
| import { SelectWithSearch } from '@/components/originui/select-with-search'; | |||
| import { TopNFormField } from '@/components/top-n-item'; | |||
| import { | |||
| Form, | |||
| @@ -7,42 +9,77 @@ import { | |||
| FormLabel, | |||
| FormMessage, | |||
| } from '@/components/ui/form'; | |||
| import { RAGFlowSelect } from '@/components/ui/select'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||
| import { memo } from 'react'; | |||
| import { useForm, useFormContext } from 'react-hook-form'; | |||
| import { z } from 'zod'; | |||
| import { initialWikipediaValues } from '../../constant'; | |||
| import { useFormValues } from '../../hooks/use-form-values'; | |||
| import { INextOperatorForm } from '../../interface'; | |||
| import { LanguageOptions } from '../../options'; | |||
| import { DynamicInputVariable } from '../components/next-dynamic-input-variable'; | |||
| import { buildOutputList } from '../../utils/build-output-list'; | |||
| import { FormWrapper } from '../components/form-wrapper'; | |||
| import { Output } from '../components/output'; | |||
| import { QueryVariable } from '../components/query-variable'; | |||
| const WikipediaForm = ({ form, node }: INextOperatorForm) => { | |||
| export const WikipediaFormPartialSchema = { | |||
| top_n: z.string(), | |||
| language: z.string(), | |||
| }; | |||
| const FormSchema = z.object({ | |||
| query: z.string(), | |||
| ...WikipediaFormPartialSchema, | |||
| }); | |||
| export function WikipediaFormWidgets() { | |||
| const { t } = useTranslate('common'); | |||
| const form = useFormContext(); | |||
| return ( | |||
| <> | |||
| <TopNFormField></TopNFormField> | |||
| <FormField | |||
| control={form.control} | |||
| name="language" | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| <FormLabel>{t('language')}</FormLabel> | |||
| <FormControl> | |||
| <SelectWithSearch {...field} options={LanguageOptions} /> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| </> | |||
| ); | |||
| } | |||
| const outputList = buildOutputList(initialWikipediaValues.outputs); | |||
| function WikipediaForm({ node }: INextOperatorForm) { | |||
| const defaultValues = useFormValues(initialWikipediaValues, node); | |||
| const form = useForm<z.infer<typeof FormSchema>>({ | |||
| defaultValues, | |||
| resolver: zodResolver(FormSchema), | |||
| }); | |||
| return ( | |||
| <Form {...form}> | |||
| <form | |||
| className="space-y-6" | |||
| onSubmit={(e) => { | |||
| e.preventDefault(); | |||
| }} | |||
| > | |||
| <DynamicInputVariable node={node}></DynamicInputVariable> | |||
| <TopNFormField></TopNFormField> | |||
| <FormField | |||
| control={form.control} | |||
| name="language" | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| <FormLabel>{t('language')}</FormLabel> | |||
| <FormControl> | |||
| <RAGFlowSelect {...field} options={LanguageOptions} /> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| </form> | |||
| <FormWrapper> | |||
| <FormContainer> | |||
| <QueryVariable></QueryVariable> | |||
| <WikipediaFormWidgets></WikipediaFormWidgets> | |||
| </FormContainer> | |||
| </FormWrapper> | |||
| <div className="p-5"> | |||
| <Output list={outputList}></Output> | |||
| </div> | |||
| </Form> | |||
| ); | |||
| }; | |||
| } | |||
| export default WikipediaForm; | |||
| export default memo(WikipediaForm); | |||
| @@ -1,4 +1,4 @@ | |||
| import { omit } from 'lodash'; | |||
| import { omit, pick } from 'lodash'; | |||
| import { useCallback } from 'react'; | |||
| import { Operator } from '../constant'; | |||
| import { useInitializeOperatorParams } from './use-add-node'; | |||
| @@ -27,6 +27,22 @@ export function useAgentToolInitialValues() { | |||
| case Operator.YahooFinance: | |||
| return omit(initialValues, 'stock_code'); | |||
| case Operator.Email: | |||
| return pick( | |||
| initialValues, | |||
| 'smtp_server', | |||
| 'smtp_port', | |||
| 'email', | |||
| 'password', | |||
| 'sender_name', | |||
| ); | |||
| case Operator.DuckDuckGo: | |||
| return pick(initialValues, 'top_n', 'channel'); | |||
| case Operator.Wikipedia: | |||
| return pick(initialValues, 'top_n', 'language'); | |||
| default: | |||
| return initialValues; | |||
| } | |||