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 retrieval tool #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,6 @@ import {
|
||||
FormItem,
|
||||
FormLabel,
|
||||
} from '@/components/ui/form';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Position } from '@xyflow/react';
|
||||
import { useContext, useMemo } from 'react';
|
||||
@ -22,6 +21,7 @@ import { AgentInstanceContext } from '../../context';
|
||||
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 { AgentTools } from './agent-tools';
|
||||
@ -85,20 +85,7 @@ const AgentForm = ({ node }: INextOperatorForm) => {
|
||||
}}
|
||||
>
|
||||
<FormContainer>
|
||||
{isSubAgent && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`description`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1">
|
||||
<FormLabel>Description</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea {...field}></Textarea>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{isSubAgent && <DescriptionField></DescriptionField>}
|
||||
<LargeModelFormField></LargeModelFormField>
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
||||
@ -42,6 +42,7 @@ const Menus = [
|
||||
Operator.Invoke,
|
||||
Operator.Crawler,
|
||||
Operator.Code,
|
||||
Operator.Retrieval,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { IAgentForm } from '@/interfaces/database/agent';
|
||||
import { DefaultAgentToolValuesMap } from '@/pages/agent/constant';
|
||||
import { AgentFormContext } from '@/pages/agent/context';
|
||||
import useGraphStore from '@/pages/agent/store';
|
||||
import { get } from 'lodash';
|
||||
@ -23,7 +24,17 @@ export function useUpdateAgentNodeTools() {
|
||||
if (node?.id) {
|
||||
const nextValue = value.reduce<IAgentForm['tools']>((pre, cur) => {
|
||||
const tool = tools.find((x) => x.component_name === cur);
|
||||
pre.push(tool ? tool : { component_name: cur, params: {} });
|
||||
pre.push(
|
||||
tool
|
||||
? tool
|
||||
: {
|
||||
component_name: cur,
|
||||
params:
|
||||
DefaultAgentToolValuesMap[
|
||||
cur as keyof typeof DefaultAgentToolValuesMap
|
||||
] || {},
|
||||
},
|
||||
);
|
||||
return pre;
|
||||
}, []);
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import {
|
||||
BaiduFanyiDomainOptions,
|
||||
BaiduFanyiSourceLangOptions,
|
||||
} from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
} from '../../options';
|
||||
import DynamicInputVariable from '../components/dynamic-input-variable';
|
||||
|
||||
const BaiduFanyiForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
|
||||
@ -2,8 +2,8 @@ import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { BingCountryOptions, BingLanguageOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import { BingCountryOptions, BingLanguageOptions } from '../../options';
|
||||
import DynamicInputVariable from '../components/dynamic-input-variable';
|
||||
|
||||
const BingForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
|
||||
26
web/src/pages/agent/form/components/description-field.tsx
Normal file
26
web/src/pages/agent/form/components/description-field.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
} from '@/components/ui/form';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
|
||||
export function DescriptionField() {
|
||||
const form = useFormContext();
|
||||
return (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`description`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1">
|
||||
<FormLabel>Description</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea {...field}></Textarea>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { CrawlerResultOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import { CrawlerResultOptions } from '../../options';
|
||||
import DynamicInputVariable from '../components/dynamic-input-variable';
|
||||
const CrawlerForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Select } from 'antd';
|
||||
import { DeepLSourceLangOptions, DeepLTargetLangOptions } from '../../constant';
|
||||
import { useBuildSortOptions } from '../../form-hooks';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import { DeepLSourceLangOptions, DeepLTargetLangOptions } from '../../options';
|
||||
import DynamicInputVariable from '../components/dynamic-input-variable';
|
||||
|
||||
const DeepLForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
|
||||
@ -4,8 +4,8 @@ import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { useTestDbConnect } from '@/hooks/flow-hooks';
|
||||
import { Button, Flex, Form, Input, InputNumber, Select } from 'antd';
|
||||
import { useCallback } from 'react';
|
||||
import { ExeSQLOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import { ExeSQLOptions } from '../../options';
|
||||
import DynamicInputVariable from '../components/dynamic-input-variable';
|
||||
|
||||
const ExeSQLForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { GoogleCountryOptions, GoogleLanguageOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import { GoogleCountryOptions, GoogleLanguageOptions } from '../../options';
|
||||
import DynamicInputVariable from '../components/dynamic-input-variable';
|
||||
|
||||
const GoogleForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import {
|
||||
Jin10CalendarDatashapeOptions,
|
||||
Jin10CalendarTypeOptions,
|
||||
@ -8,8 +9,7 @@ import {
|
||||
Jin10SymbolsDatatypeOptions,
|
||||
Jin10SymbolsTypeOptions,
|
||||
Jin10TypeOptions,
|
||||
} from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
} from '../../options';
|
||||
import DynamicInputVariable from '../components/dynamic-input-variable';
|
||||
|
||||
const Jin10Form = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
|
||||
@ -10,13 +10,13 @@ import { Input } from '@/components/ui/input';
|
||||
import { RAGFlowSelect } from '@/components/ui/select';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { INextOperatorForm } from '../../interface';
|
||||
import {
|
||||
QWeatherLangOptions,
|
||||
QWeatherTimePeriodOptions,
|
||||
QWeatherTypeOptions,
|
||||
QWeatherUserTypeOptions,
|
||||
} from '../../constant';
|
||||
import { INextOperatorForm } from '../../interface';
|
||||
} from '../../options';
|
||||
import { DynamicInputVariable } from '../components/next-dynamic-input-variable';
|
||||
|
||||
enum FormFieldName {
|
||||
|
||||
@ -14,7 +14,7 @@ import {
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useMemo } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useForm, useFormContext } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { z } from 'zod';
|
||||
import { initialRetrievalValues } from '../../constant';
|
||||
@ -24,8 +24,7 @@ import { Output } from '../components/output';
|
||||
import { QueryVariable } from '../components/query-variable';
|
||||
import { useValues } from './use-values';
|
||||
|
||||
const FormSchema = z.object({
|
||||
query: z.string().optional(),
|
||||
export const RetrievalPartialSchema = {
|
||||
similarity_threshold: z.coerce.number(),
|
||||
keywords_similarity_weight: z.coerce.number(),
|
||||
top_n: z.coerce.number(),
|
||||
@ -33,11 +32,40 @@ const FormSchema = z.object({
|
||||
kb_ids: z.array(z.string()),
|
||||
rerank_id: z.string(),
|
||||
empty_response: z.string(),
|
||||
};
|
||||
|
||||
export const FormSchema = z.object({
|
||||
query: z.string().optional(),
|
||||
...RetrievalPartialSchema,
|
||||
});
|
||||
|
||||
const RetrievalForm = ({ node }: INextOperatorForm) => {
|
||||
export function EmptyResponseField() {
|
||||
const { t } = useTranslation();
|
||||
const form = useFormContext();
|
||||
|
||||
return (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="empty_response"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('chat.emptyResponse')}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
placeholder={t('common.namePlaceholder')}
|
||||
{...field}
|
||||
autoComplete="off"
|
||||
rows={4}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const RetrievalForm = ({ node }: INextOperatorForm) => {
|
||||
const outputList = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
@ -75,25 +103,7 @@ const RetrievalForm = ({ node }: INextOperatorForm) => {
|
||||
></SimilaritySliderFormField>
|
||||
<TopNFormField></TopNFormField>
|
||||
<RerankFormFields></RerankFormFields>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="empty_response"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('chat.emptyResponse')}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
placeholder={t('common.namePlaceholder')}
|
||||
{...field}
|
||||
autoComplete="off"
|
||||
rows={4}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<EmptyResponseField></EmptyResponseField>
|
||||
</FormContainer>
|
||||
<Output list={outputList}></Output>
|
||||
</form>
|
||||
|
||||
@ -10,8 +10,8 @@ import {
|
||||
} from '@/components/ui/form';
|
||||
import { RAGFlowSelect } from '@/components/ui/select';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { GoogleLanguageOptions } from '../../constant';
|
||||
import { INextOperatorForm } from '../../interface';
|
||||
import { GoogleLanguageOptions } from '../../options';
|
||||
|
||||
const RewriteQuestionForm = ({ form }: INextOperatorForm) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -12,9 +12,9 @@ import GithubForm from '../github-form';
|
||||
import GoogleForm from '../google-form';
|
||||
import GoogleScholarForm from '../google-scholar-form';
|
||||
import PubMedForm from '../pubmed-form';
|
||||
import RetrievalForm from '../retrieval-form/next';
|
||||
import WikipediaForm from '../wikipedia-form';
|
||||
import YahooFinanceForm from '../yahoo-finance-form';
|
||||
import RetrievalForm from './retrieval-form';
|
||||
import TavilyForm from './tavily-form';
|
||||
|
||||
export const ToolFormConfigMap = {
|
||||
|
||||
59
web/src/pages/agent/form/tool-form/retrieval-form/index.tsx
Normal file
59
web/src/pages/agent/form/tool-form/retrieval-form/index.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import { FormContainer } from '@/components/form-container';
|
||||
import { KnowledgeBaseFormField } from '@/components/knowledge-base-item';
|
||||
import { RerankFormFields } from '@/components/rerank';
|
||||
import { SimilaritySliderFormField } from '@/components/similarity-slider';
|
||||
import { TopNFormField } from '@/components/top-n-item';
|
||||
import { Form } from '@/components/ui/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { DescriptionField } from '../../components/description-field';
|
||||
import {
|
||||
EmptyResponseField,
|
||||
RetrievalPartialSchema,
|
||||
} from '../../retrieval-form/next';
|
||||
import { useValues } from '../use-values';
|
||||
import { useWatchFormChange } from '../use-watch-change';
|
||||
|
||||
export const FormSchema = z.object({
|
||||
...RetrievalPartialSchema,
|
||||
description: z.string().optional(),
|
||||
});
|
||||
|
||||
const RetrievalForm = () => {
|
||||
const defaultValues = useValues();
|
||||
|
||||
const form = useForm({
|
||||
defaultValues: defaultValues,
|
||||
resolver: zodResolver(FormSchema),
|
||||
});
|
||||
|
||||
useWatchFormChange(form);
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className="space-y-6 p-4"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
<FormContainer>
|
||||
<DescriptionField></DescriptionField>
|
||||
<KnowledgeBaseFormField></KnowledgeBaseFormField>
|
||||
</FormContainer>
|
||||
<FormContainer>
|
||||
<SimilaritySliderFormField
|
||||
vectorSimilarityWeightName="keywords_similarity_weight"
|
||||
isTooltipShown
|
||||
></SimilaritySliderFormField>
|
||||
<TopNFormField></TopNFormField>
|
||||
<RerankFormFields></RerankFormFields>
|
||||
<EmptyResponseField></EmptyResponseField>
|
||||
</FormContainer>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default RetrievalForm;
|
||||
@ -1,5 +1,6 @@
|
||||
import { isEmpty } from 'lodash';
|
||||
import { useMemo } from 'react';
|
||||
import { DefaultAgentToolValuesMap } from '../../constant';
|
||||
import useGraphStore from '../../store';
|
||||
import { getAgentNodeTools } from '../../utils';
|
||||
|
||||
@ -13,10 +14,6 @@ export enum Topic {
|
||||
General = 'general',
|
||||
}
|
||||
|
||||
export const defaultValues = {
|
||||
api_key: '',
|
||||
};
|
||||
|
||||
export function useValues() {
|
||||
const { clickedToolId, clickedNodeId, findUpstreamNodeById } = useGraphStore(
|
||||
(state) => state,
|
||||
@ -31,6 +28,11 @@ export function useValues() {
|
||||
)?.params;
|
||||
|
||||
if (isEmpty(formData)) {
|
||||
const defaultValues =
|
||||
DefaultAgentToolValuesMap[
|
||||
clickedToolId as keyof typeof DefaultAgentToolValuesMap
|
||||
];
|
||||
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@ import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { DatePicker, DatePickerProps, Form, Input, Select } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { TuShareSrcOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import { TuShareSrcOptions } from '../../options';
|
||||
import DynamicInputVariable from '../components/dynamic-input-variable';
|
||||
|
||||
const DateTimePicker = ({
|
||||
|
||||
@ -10,8 +10,8 @@ import {
|
||||
import { RAGFlowSelect } from '@/components/ui/select';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { WenCaiQueryTypeOptions } from '../../constant';
|
||||
import { INextOperatorForm } from '../../interface';
|
||||
import { WenCaiQueryTypeOptions } from '../../options';
|
||||
import { DynamicInputVariable } from '../components/next-dynamic-input-variable';
|
||||
|
||||
const WenCaiForm = ({ form, node }: INextOperatorForm) => {
|
||||
|
||||
@ -9,8 +9,8 @@ import {
|
||||
} from '@/components/ui/form';
|
||||
import { RAGFlowSelect } from '@/components/ui/select';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { LanguageOptions } from '../../constant';
|
||||
import { INextOperatorForm } from '../../interface';
|
||||
import { LanguageOptions } from '../../options';
|
||||
import { DynamicInputVariable } from '../components/next-dynamic-input-variable';
|
||||
|
||||
const WikipediaForm = ({ form, node }: INextOperatorForm) => {
|
||||
|
||||
@ -186,11 +186,9 @@ function useAddChildEdge() {
|
||||
}
|
||||
|
||||
function useAddToolNode() {
|
||||
const addNode = useGraphStore((state) => state.addNode);
|
||||
const getNode = useGraphStore((state) => state.getNode);
|
||||
const addEdge = useGraphStore((state) => state.addEdge);
|
||||
const edges = useGraphStore((state) => state.edges);
|
||||
const nodes = useGraphStore((state) => state.nodes);
|
||||
const { nodes, edges, addEdge, getNode, addNode } = useGraphStore(
|
||||
(state) => state,
|
||||
);
|
||||
|
||||
const addToolNode = useCallback(
|
||||
(newNode: Node<any>, nodeId?: string) => {
|
||||
|
||||
2170
web/src/pages/agent/options.ts
Normal file
2170
web/src/pages/agent/options.ts
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user