Pārlūkot izejas kodu

Feat: Add invoke and github operators #3221 (#9112)

### What problem does this PR solve?

Feat: Add invoke and github operators #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
tags/v0.20.0
balibabu pirms 3 mēnešiem
vecāks
revīzija
523e61ae18
Revīzijas autora e-pasta adrese nav piesaistīta nevienam kontam

+ 1
- 0
web/src/locales/en.ts Parādīt failu

@@ -1308,6 +1308,7 @@ This delimiter is used to split the input text into several text pieces echo of
management: 'Management',
import: 'Import',
export: 'Export',
seconds: 'Seconds',
},
llmTools: {
bad_calculator: {

+ 3
- 0
web/src/pages/agent/canvas/node/dropdown/next-step-dropdown.tsx Parādīt failu

@@ -109,6 +109,9 @@ function AccordionOperators() {
Operator.Wikipedia,
Operator.GoogleScholar,
Operator.ArXiv,
Operator.PubMed,
Operator.GitHub,
Operator.Invoke,
]}
></OperatorItemList>
</AccordionContent>

+ 23
- 6
web/src/pages/agent/constant.tsx Parādīt failu

@@ -372,9 +372,15 @@ export const initialWikipediaValues = {
};

export const initialPubMedValues = {
top_n: 10,
top_n: 12,
email: '',
...initialQueryBaseValues,
query: AgentGlobals.SysQuery,
outputs: {
formalized_content: {
value: '',
type: 'string',
},
},
};

export const initialArXivValues = {
@@ -444,7 +450,17 @@ export const initialDeepLValues = {

export const initialGithubValues = {
top_n: 5,
...initialQueryBaseValues,
query: AgentGlobals.SysQuery,
outputs: {
formalized_content: {
value: '',
type: 'string',
},
json: {
value: [],
type: 'Array<Object>',
},
},
};

export const initialBaiduFanyiValues = {
@@ -540,7 +556,7 @@ export const initialCrawlerValues = {
};

export const initialInvokeValues = {
url: 'http://',
url: '',
method: 'GET',
timeout: 60,
headers: `{
@@ -548,8 +564,9 @@ export const initialInvokeValues = {
"Cache-Control": "no-cache",
"Connection": "keep-alive"
}`,
proxy: 'http://',
proxy: '',
clean_html: false,
variables: [],
};

export const initialTemplateValues = {
@@ -852,7 +869,7 @@ export const NodeMap = {
[Operator.TuShare]: 'ragNode',
[Operator.Note]: 'noteNode',
[Operator.Crawler]: 'ragNode',
[Operator.Invoke]: 'invokeNode',
[Operator.Invoke]: 'ragNode',
[Operator.Template]: 'templateNode',
[Operator.Email]: 'ragNode',
[Operator.Iteration]: 'group',

+ 1
- 1
web/src/pages/agent/form/agent-form/index.tsx Parādīt failu

@@ -126,7 +126,7 @@ function AgentForm({ node }: INextOperatorForm) {
name={`sys_prompt`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Prompt</FormLabel>
<FormLabel>System Prompt</FormLabel>
<FormControl>
<PromptEditor
{...field}

+ 1
- 7
web/src/pages/agent/form/agent-form/tool-popover/tool-command.tsx Parādīt failu

@@ -39,13 +39,7 @@ const Menus = [
},
{
label: 'Developer',
list: [
Operator.GitHub,
Operator.ExeSQL,
Operator.Invoke,
Operator.Code,
Operator.Retrieval,
],
list: [Operator.GitHub, Operator.ExeSQL, Operator.Code, Operator.Retrieval],
},
];


+ 47
- 16
web/src/pages/agent/form/github-form/index.tsx Parādīt failu

@@ -1,21 +1,52 @@
import TopNItem from '@/components/top-n-item';
import { Form } from 'antd';
import { IOperatorForm } from '../../interface';
import DynamicInputVariable from '../components/dynamic-input-variable';
import { FormContainer } from '@/components/form-container';
import { TopNFormField } from '@/components/top-n-item';
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 { initialGithubValues } from '../../constant';
import { useFormValues } from '../../hooks/use-form-values';
import { useWatchFormChange } from '../../hooks/use-watch-form-change';
import { INextOperatorForm } from '../../interface';
import { buildOutputList } from '../../utils/build-output-list';
import { FormWrapper } from '../components/form-wrapper';
import { Output } from '../components/output';
import { QueryVariable } from '../components/query-variable';

export const FormSchema = z.object({
query: z.string(),
top_n: z.number(),
});

const outputList = buildOutputList(initialGithubValues.outputs);

function GithubForm({ node }: INextOperatorForm) {
const defaultValues = useFormValues(initialGithubValues, node);

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues,
resolver: zodResolver(FormSchema),
mode: 'onChange',
});

useWatchFormChange(node?.id, form);

const GithubForm = ({ onValuesChange, form, node }: IOperatorForm) => {
return (
<Form
name="basic"
autoComplete="off"
form={form}
onValuesChange={onValuesChange}
layout={'vertical'}
>
<DynamicInputVariable node={node}></DynamicInputVariable>
<TopNItem initialValue={5}></TopNItem>
<Form {...form}>
<FormWrapper>
<FormContainer>
<QueryVariable></QueryVariable>
</FormContainer>
<FormContainer>
<TopNFormField></TopNFormField>
</FormContainer>
</FormWrapper>
<div className="p-5">
<Output list={outputList}></Output>
</div>
</Form>
);
};
}

export default GithubForm;
export default memo(GithubForm);

+ 0
- 131
web/src/pages/agent/form/invoke-form/dynamic-variables.tsx Parādīt failu

@@ -1,131 +0,0 @@
import { EditableCell, EditableRow } from '@/components/editable-cell';
import { useTranslate } from '@/hooks/common-hooks';
import { DeleteOutlined } from '@ant-design/icons';
import { Button, Collapse, Flex, Input, Select, Table, TableProps } from 'antd';
import { trim } from 'lodash';
import { useBuildVariableOptions } from '../../hooks/use-get-begin-query';
import { IInvokeVariable } from '../../interface';
import { useHandleOperateParameters } from './hooks';

import { RAGFlowNodeType } from '@/interfaces/database/flow';
import styles from './index.less';

interface IProps {
node?: RAGFlowNodeType;
}

const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};

const DynamicVariablesForm = ({ node }: IProps) => {
const nodeId = node?.id;
const { t } = useTranslate('flow');

const options = useBuildVariableOptions(nodeId, node?.parentId);
const {
dataSource,
handleAdd,
handleRemove,
handleSave,
handleComponentIdChange,
handleValueChange,
} = useHandleOperateParameters(nodeId!);

const columns: TableProps<IInvokeVariable>['columns'] = [
{
title: t('key'),
dataIndex: 'key',
key: 'key',
onCell: (record: IInvokeVariable) => ({
record,
editable: true,
dataIndex: 'key',
title: 'key',
handleSave,
}),
},
{
title: t('componentId'),
dataIndex: 'component_id',
key: 'component_id',
align: 'center',
width: 140,
render(text, record) {
return (
<Select
style={{ width: '100%' }}
allowClear
options={options}
value={text}
disabled={trim(record.value) !== ''}
onChange={handleComponentIdChange(record)}
/>
);
},
},
{
title: t('value'),
dataIndex: 'value',
key: 'value',
align: 'center',
width: 140,
render(text, record) {
return (
<Input
value={text}
disabled={!!record.component_id}
onChange={handleValueChange(record)}
/>
);
},
},
{
title: t('operation'),
dataIndex: 'operation',
width: 20,
key: 'operation',
align: 'center',
fixed: 'right',
render(_, record) {
return <DeleteOutlined onClick={handleRemove(record.id)} />;
},
},
];

return (
<Collapse
className={styles.dynamicParameterVariable}
defaultActiveKey={['1']}
items={[
{
key: '1',
label: (
<Flex justify={'space-between'}>
<span className={styles.title}>{t('parameter')}</span>
<Button size="small" onClick={handleAdd}>
{t('add')}
</Button>
</Flex>
),
children: (
<Table
dataSource={dataSource}
columns={columns}
rowKey={'id'}
components={components}
rowClassName={() => styles.editableRow}
scroll={{ x: true }}
bordered
/>
),
},
]}
/>
);
};

export default DynamicVariablesForm;

+ 186
- 45
web/src/pages/agent/form/invoke-form/index.tsx Parādīt failu

@@ -1,8 +1,33 @@
import { Collapse } from '@/components/collapse';
import { FormContainer } from '@/components/form-container';
import NumberInput from '@/components/originui/number-input';
import { SelectWithSearch } from '@/components/originui/select-with-search';
import { Button } from '@/components/ui/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Switch } from '@/components/ui/switch';
import { zodResolver } from '@hookform/resolvers/zod';
import Editor, { loader } from '@monaco-editor/react';
import { Form, Input, InputNumber, Select, Space, Switch } from 'antd';
import { Plus } from 'lucide-react';
import { memo } from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { IOperatorForm } from '../../interface';
import DynamicVariablesForm from './dynamic-variables';
import { initialInvokeValues } from '../../constant';
import { useFormValues } from '../../hooks/use-form-values';
import { useWatchFormChange } from '../../hooks/use-watch-form-change';
import { INextOperatorForm } from '../../interface';
import { FormWrapper } from '../components/form-wrapper';
import { FormSchema, FormSchemaType } from './schema';
import { useEditVariableRecord } from './use-edit-variable';
import { VariableDialog } from './variable-dialog';
import { VariableTable } from './variable-table';

loader.config({ paths: { vs: '/vs' } });

@@ -25,54 +50,170 @@ interface TimeoutInputProps {
const TimeoutInput = ({ value, onChange }: TimeoutInputProps) => {
const { t } = useTranslation();
return (
<Space>
<InputNumber value={value} onChange={onChange} /> {t('common.s')}
</Space>
<div className="flex gap-2 items-center">
<NumberInput value={value} onChange={onChange} /> {t('flow.seconds')}
</div>
);
};

const InvokeForm = ({ onValuesChange, form, node }: IOperatorForm) => {
function InvokeForm({ node }: INextOperatorForm) {
const { t } = useTranslation();
const defaultValues = useFormValues(initialInvokeValues, node);

const form = useForm<FormSchemaType>({
defaultValues,
resolver: zodResolver(FormSchema),
mode: 'onChange',
});

const {
visible,
hideModal,
showModal,
ok,
currentRecord,
otherThanCurrentQuery,
handleDeleteRecord,
} = useEditVariableRecord({
form,
node,
});

const variables = useWatch({ control: form.control, name: 'variables' });

useWatchFormChange(node?.id, form);

return (
<>
<Form
name="basic"
autoComplete="off"
form={form}
onValuesChange={onValuesChange}
layout={'vertical'}
>
<Form.Item name={'url'} label={t('flow.url')}>
<Input />
</Form.Item>
<Form.Item
name={'method'}
label={t('flow.method')}
initialValue={Method.GET}
<Form {...form}>
<FormWrapper>
<FormContainer>
<FormField
control={form.control}
name="url"
render={({ field }) => (
<FormItem>
<FormLabel>{t('flow.url')}</FormLabel>
<FormControl>
<Input {...field} placeholder="http://" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="method"
render={({ field }) => (
<FormItem>
<FormLabel>{t('flow.method')}</FormLabel>
<FormControl>
<SelectWithSearch {...field} options={MethodOptions} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="timeout"
render={({ field }) => (
<FormItem>
<FormLabel>{t('flow.timeout')}</FormLabel>
<FormControl>
<TimeoutInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="headers"
render={({ field }) => (
<FormItem>
<FormLabel>{t('flow.headers')}</FormLabel>
<FormControl>
<Editor
height={200}
defaultLanguage="json"
theme="vs-dark"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="proxy"
render={({ field }) => (
<FormItem>
<FormLabel>{t('flow.proxy')}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="clean_html"
render={({ field }) => (
<FormItem>
<FormLabel tooltip={t('flow.cleanHtmlTip')}>
{t('flow.cleanHtml')}
</FormLabel>
<FormControl>
<Switch
onCheckedChange={field.onChange}
checked={field.value}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Create a hidden field to make Form instance record this */}
<FormField
control={form.control}
name={'variables'}
render={() => <div></div>}
/>
</FormContainer>
<Collapse
title={<div>{t('flow.parameter')}</div>}
rightContent={
<Button
variant={'ghost'}
onClick={(e) => {
e.preventDefault();
showModal();
}}
>
<Plus />
</Button>
}
>
<Select options={MethodOptions} />
</Form.Item>
<Form.Item name={'timeout'} label={t('flow.timeout')}>
<TimeoutInput></TimeoutInput>
</Form.Item>
<Form.Item name={'headers'} label={t('flow.headers')}>
<Editor height={200} defaultLanguage="json" theme="vs-dark" />
</Form.Item>
<Form.Item name={'proxy'} label={t('flow.proxy')}>
<Input />
</Form.Item>
<Form.Item
name={'clean_html'}
label={t('flow.cleanHtml')}
tooltip={t('flow.cleanHtmlTip')}
>
<Switch />
</Form.Item>
<DynamicVariablesForm node={node}></DynamicVariablesForm>
</Form>
</>
<VariableTable
data={variables}
showModal={showModal}
deleteRecord={handleDeleteRecord}
nodeId={node?.id}
></VariableTable>
</Collapse>
{visible && (
<VariableDialog
hideModal={hideModal}
initialValue={currentRecord}
otherThanCurrentQuery={otherThanCurrentQuery}
submit={ok}
></VariableDialog>
)}
</FormWrapper>
</Form>
);
};
}

export default InvokeForm;
export default memo(InvokeForm);

+ 21
- 0
web/src/pages/agent/form/invoke-form/schema.ts Parādīt failu

@@ -0,0 +1,21 @@
import { z } from 'zod';

export const VariableFormSchema = z.object({
key: z.string(),
ref: z.string(),
value: z.string(),
});

export const FormSchema = z.object({
url: z.string().url(),
method: z.string(),
timeout: z.number(),
headers: z.string(),
proxy: z.string().url(),
clean_html: z.boolean(),
variables: z.array(VariableFormSchema),
});

export type FormSchemaType = z.infer<typeof FormSchema>;

export type VariableFormSchemaType = z.infer<typeof VariableFormSchema>;

+ 70
- 0
web/src/pages/agent/form/invoke-form/use-edit-variable.ts Parādīt failu

@@ -0,0 +1,70 @@
import { useSetModalState } from '@/hooks/common-hooks';
import { useSetSelectedRecord } from '@/hooks/logic-hooks';
import { useCallback, useMemo, useState } from 'react';
import { UseFormReturn, useWatch } from 'react-hook-form';
import { INextOperatorForm } from '../../interface';
import { FormSchemaType, VariableFormSchemaType } from './schema';

export const useEditVariableRecord = ({
form,
}: INextOperatorForm & { form: UseFormReturn<FormSchemaType> }) => {
const { setRecord, currentRecord } =
useSetSelectedRecord<VariableFormSchemaType>();

const { visible, hideModal, showModal } = useSetModalState();
const [index, setIndex] = useState(-1);
const variables = useWatch({
control: form.control,
name: 'variables',
});

const otherThanCurrentQuery = useMemo(() => {
return variables.filter((item, idx) => idx !== index);
}, [index, variables]);

const handleEditRecord = useCallback(
(record: VariableFormSchemaType) => {
const variables = form?.getValues('variables') || [];

const nextVaribales =
index > -1
? variables.toSpliced(index, 1, record)
: [...variables, record];

form.setValue('variables', nextVaribales);

hideModal();
},
[form, hideModal, index],
);

const handleShowModal = useCallback(
(idx?: number, record?: VariableFormSchemaType) => {
setIndex(idx ?? -1);
setRecord(record ?? ({} as VariableFormSchemaType));
showModal();
},
[setRecord, showModal],
);

const handleDeleteRecord = useCallback(
(idx: number) => {
const variables = form?.getValues('variables') || [];
const nextVariables = variables.filter((item, index) => index !== idx);

form.setValue('variables', nextVariables);
},
[form],
);

return {
ok: handleEditRecord,
currentRecord,
setRecord,
visible,
hideModal,
showModal: handleShowModal,
otherThanCurrentQuery,
handleDeleteRecord,
};
};

+ 143
- 0
web/src/pages/agent/form/invoke-form/variable-dialog.tsx Parādīt failu

@@ -0,0 +1,143 @@
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { IModalProps } from '@/interfaces/common';
import { zodResolver } from '@hookform/resolvers/zod';
import { isEmpty } from 'lodash';
import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import { QueryVariable } from '../components/query-variable';
import { VariableFormSchemaType } from './schema';

type ModalFormProps = {
initialValue: VariableFormSchemaType;
otherThanCurrentQuery: VariableFormSchemaType[];
submit(values: any): void;
};

const FormId = 'BeginParameterForm';

function VariableForm({
initialValue,
otherThanCurrentQuery,
submit,
}: ModalFormProps) {
const { t } = useTranslation();
const FormSchema = z.object({
key: z
.string()
.trim()
.min(1)
.refine(
(value) =>
!value || !otherThanCurrentQuery.some((x) => x.key === value),
{ message: 'The key cannot be repeated!' },
),
ref: z.string(),
value: z.string(),
});

const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
mode: 'onChange',
defaultValues: {
key: '',
value: '',
ref: '',
},
});

useEffect(() => {
if (!isEmpty(initialValue)) {
form.reset(initialValue);
}
}, [form, initialValue]);

function onSubmit(data: z.infer<typeof FormSchema>) {
submit(data);
}

return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
id={FormId}
className="space-y-5"
autoComplete="off"
>
<FormField
name="key"
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>{t('flow.key')}</FormLabel>
<FormControl>
<Input {...field} autoComplete="off" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<QueryVariable name="ref" label={t('flow.ref')}></QueryVariable>
<FormField
name="value"
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>{t('flow.value')}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</form>
</Form>
);
}

export function VariableDialog({
initialValue,
hideModal,
otherThanCurrentQuery,
submit,
}: ModalFormProps & IModalProps<VariableFormSchemaType>) {
const { t } = useTranslation();

return (
<Dialog open onOpenChange={hideModal}>
<DialogContent>
<DialogHeader>
<DialogTitle>{t('flow.variableSettings')}</DialogTitle>
</DialogHeader>
<VariableForm
initialValue={initialValue}
otherThanCurrentQuery={otherThanCurrentQuery}
submit={submit}
></VariableForm>
<DialogFooter>
<Button type="submit" form={FormId}>
Confirm
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

+ 199
- 0
web/src/pages/agent/form/invoke-form/variable-table.tsx Parādīt failu

@@ -0,0 +1,199 @@
'use client';

import {
ColumnDef,
ColumnFiltersState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from '@tanstack/react-table';
import { Pencil, Trash2 } from 'lucide-react';
import * as React from 'react';

import { TableEmpty } from '@/components/table-skeleton';
import { Button } from '@/components/ui/button';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
import { useTranslation } from 'react-i18next';
import { useGetVariableLabelByValue } from '../../hooks/use-get-begin-query';
import { VariableFormSchemaType } from './schema';

interface IProps {
data: VariableFormSchemaType[];
deleteRecord(index: number): void;
showModal(index: number, record: VariableFormSchemaType): void;
nodeId?: string;
}

export function VariableTable({
data = [],
deleteRecord,
showModal,
nodeId,
}: IProps) {
const { t } = useTranslation();
const getLabel = useGetVariableLabelByValue(nodeId!);

const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[],
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});

const columns: ColumnDef<VariableFormSchemaType>[] = [
{
accessorKey: 'key',
header: 'key',
meta: { cellClassName: 'max-w-30' },
cell: ({ row }) => {
const key: string = row.getValue('key');
return (
<Tooltip>
<TooltipTrigger asChild>
<div className="truncate">{key}</div>
</TooltipTrigger>
<TooltipContent>
<p>{key}</p>
</TooltipContent>
</Tooltip>
);
},
},
{
accessorKey: 'ref',
header: t('flow.ref'),
meta: { cellClassName: 'max-w-30' },
cell: ({ row }) => {
const ref: string = row.getValue('ref');
const label = getLabel(ref);
return (
<Tooltip>
<TooltipTrigger asChild>
<div className="truncate">{label}</div>
</TooltipTrigger>
<TooltipContent>
<p>{label}</p>
</TooltipContent>
</Tooltip>
);
},
},
{
accessorKey: 'value',
header: t('flow.value'),
cell: ({ row }) => <div>{row.getValue('value')}</div>,
},
{
id: 'actions',
enableHiding: false,
header: t('common.action'),
cell: ({ row }) => {
const record = row.original;
const idx = row.index;

return (
<div>
<Button
className="bg-transparent text-foreground hover:bg-muted-foreground hover:text-foreground"
onClick={() => showModal(idx, record)}
>
<Pencil />
</Button>
<Button
className="bg-transparent text-foreground hover:bg-muted-foreground hover:text-foreground"
onClick={() => deleteRecord(idx)}
>
<Trash2 />
</Button>
</div>
);
},
},
];

const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
state: {
sorting,
columnFilters,
columnVisibility,
},
});

return (
<div className="w-full">
<div className="rounded-md border">
<Table rootClassName="rounded-md">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && 'selected'}
>
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
className={cn(cell.column.columnDef.meta?.cellClassName)}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableEmpty columnsLength={columns.length}></TableEmpty>
)}
</TableBody>
</Table>
</div>
</div>
);
}

+ 70
- 26
web/src/pages/agent/form/pubmed-form/index.tsx Parādīt failu

@@ -1,3 +1,4 @@
import { FormContainer } from '@/components/form-container';
import { TopNFormField } from '@/components/top-n-item';
import {
Form,
@@ -9,38 +10,81 @@ import {
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
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 { initialPubMedValues } from '../../constant';
import { useFormValues } from '../../hooks/use-form-values';
import { useWatchFormChange } from '../../hooks/use-watch-form-change';
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 PubMedForm = ({ form, node }: INextOperatorForm) => {
export const PubMedFormPartialSchema = {
top_n: z.number(),
email: z.string().email(),
};

export const FormSchema = z.object({
...PubMedFormPartialSchema,
query: z.string(),
});

export function PubMedFormWidgets() {
const form = useFormContext();
const { t } = useTranslate('flow');

return (
<>
<TopNFormField></TopNFormField>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel tooltip={t('emailTip')}>{t('email')}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</>
);
}

const outputList = buildOutputList(initialPubMedValues.outputs);

function PubMedForm({ node }: INextOperatorForm) {
const defaultValues = useFormValues(initialPubMedValues, node);

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues,
resolver: zodResolver(FormSchema),
mode: 'onChange',
});

useWatchFormChange(node?.id, form);

return (
<Form {...form}>
<form
className="space-y-6"
onSubmit={(e) => {
e.preventDefault();
}}
>
<DynamicInputVariable node={node}></DynamicInputVariable>
<TopNFormField></TopNFormField>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel tooltip={t('emailTip')}>{t('email')}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</form>
<FormWrapper>
<FormContainer>
<QueryVariable></QueryVariable>
</FormContainer>
<FormContainer>
<PubMedFormWidgets></PubMedFormWidgets>
</FormContainer>
</FormWrapper>
<div className="p-5">
<Output list={outputList}></Output>
</div>
</Form>
);
};
}

export default PubMedForm;
export default memo(PubMedForm);

+ 2
- 2
web/src/pages/agent/form/tool-form/constant.tsx Parādīt failu

@@ -1,16 +1,16 @@
import { Operator } from '../../constant';
import AkShareForm from '../akshare-form';
import DeepLForm from '../deepl-form';
import GithubForm from '../github-form';
import PubMedForm from '../pubmed-form';
import ArXivForm from './arxiv-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 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';
import TavilyForm from './tavily-form';
import WikipediaForm from './wikipedia-form';

+ 36
- 0
web/src/pages/agent/form/tool-form/github-form/index.tsx Parādīt failu

@@ -0,0 +1,36 @@
import { FormContainer } from '@/components/form-container';
import { TopNFormField } from '@/components/top-n-item';
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 { useValues } from '../use-values';
import { useWatchFormChange } from '../use-watch-change';

function GithubForm() {
const values = useValues();

const FormSchema = z.object({ query: z.string() });

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues: values,
resolver: zodResolver(FormSchema),
mode: 'onChange',
});

useWatchFormChange(form);

return (
<Form {...form}>
<FormWrapper>
<FormContainer>
<TopNFormField></TopNFormField>
</FormContainer>
</FormWrapper>
</Form>
);
}

export default memo(GithubForm);

+ 36
- 0
web/src/pages/agent/form/tool-form/pubmed-form/index.tsx Parādīt failu

@@ -0,0 +1,36 @@
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 { PubMedFormPartialSchema, PubMedFormWidgets } from '../../pubmed-form';
import { useValues } from '../use-values';
import { useWatchFormChange } from '../use-watch-change';

function PubMedForm() {
const values = useValues();

const FormSchema = z.object(PubMedFormPartialSchema);

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues: values,
resolver: zodResolver(FormSchema),
mode: 'onChange',
});

useWatchFormChange(form);

return (
<Form {...form}>
<FormWrapper>
<FormContainer>
<PubMedFormWidgets></PubMedFormWidgets>
</FormContainer>
</FormWrapper>
</Form>
);
}

export default memo(PubMedForm);

+ 7
- 14
web/src/pages/agent/form/yahoo-finance-form/index.tsx Parādīt failu

@@ -7,7 +7,6 @@ import {
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Switch } from '@/components/ui/switch';
import { useTranslate } from '@/hooks/common-hooks';
import { zodResolver } from '@hookform/resolvers/zod';
@@ -21,6 +20,7 @@ import { INextOperatorForm } from '../../interface';
import { buildOutputList } from '../../utils/build-output-list';
import { FormWrapper } from '../components/form-wrapper';
import { Output } from '../components/output';
import { QueryVariable } from '../components/query-variable';

export const YahooFinanceFormPartialSchema = {
info: z.boolean(),
@@ -106,19 +106,12 @@ const YahooFinanceForm = ({ node }: INextOperatorForm) => {
<Form {...form}>
<FormWrapper>
<FormContainer>
<FormField
control={form.control}
name={`stock_code`}
render={({ field }) => (
<FormItem>
<FormLabel>{t('stockCode')}</FormLabel>
<FormControl>
<Input {...field}></Input>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<QueryVariable
name="stock_code"
label={t('stockCode')}
></QueryVariable>
</FormContainer>
<FormContainer>
<YahooFinanceFormWidgets></YahooFinanceFormWidgets>
</FormContainer>
</FormWrapper>

+ 4
- 0
web/src/pages/agent/hooks/use-agent-tool-initial-values.ts Parādīt failu

@@ -48,6 +48,10 @@ export function useAgentToolInitialValues() {
return omit(initialValues, 'query', 'outputs');
case Operator.ArXiv:
return pick(initialValues, 'top_n', 'sort_by');
case Operator.PubMed:
return pick(initialValues, 'top_n', 'email');
case Operator.GitHub:
return pick(initialValues, 'top_n');

default:
return initialValues;

Notiek ielāde…
Atcelt
Saglabāt