mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Save the agent tool data to the node #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -139,6 +139,29 @@ export interface ICodeForm {
|
|||||||
script?: string;
|
script?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IAgentForm {
|
||||||
|
sys_prompt: string;
|
||||||
|
prompts: Array<{
|
||||||
|
role: string;
|
||||||
|
content: string;
|
||||||
|
}>;
|
||||||
|
max_retries: number;
|
||||||
|
delay_after_error: number;
|
||||||
|
visual_files_var: string;
|
||||||
|
max_rounds: number;
|
||||||
|
exception_method: Nullable<'comment' | 'go'>;
|
||||||
|
exception_comment: any;
|
||||||
|
exception_goto: any;
|
||||||
|
tools: Array<{
|
||||||
|
component_name: string;
|
||||||
|
params: Record<string, any>;
|
||||||
|
}>;
|
||||||
|
outputs: {
|
||||||
|
structured_output: Record<string, Record<string, any>>;
|
||||||
|
content: Record<string, any>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export type BaseNodeData<TForm extends any> = {
|
export type BaseNodeData<TForm extends any> = {
|
||||||
label: string; // operator type
|
label: string; // operator type
|
||||||
name: string; // operator name
|
name: string; // operator name
|
||||||
@ -167,7 +190,7 @@ export type IIterationStartNode = BaseNode;
|
|||||||
export type IKeywordNode = BaseNode;
|
export type IKeywordNode = BaseNode;
|
||||||
export type ICodeNode = BaseNode<ICodeForm>;
|
export type ICodeNode = BaseNode<ICodeForm>;
|
||||||
export type IAgentNode = BaseNode;
|
export type IAgentNode = BaseNode;
|
||||||
export type IToolNode = BaseNode;
|
export type IToolNode = BaseNode<IAgentForm>;
|
||||||
|
|
||||||
export type RAGFlowNodeType =
|
export type RAGFlowNodeType =
|
||||||
| IBeginNode
|
| IBeginNode
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { IToolNode } from '@/interfaces/database/agent';
|
import { IAgentForm, IToolNode } from '@/interfaces/database/agent';
|
||||||
import { Handle, NodeProps, Position } from '@xyflow/react';
|
import { Handle, NodeProps, Position } from '@xyflow/react';
|
||||||
|
import { get } from 'lodash';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { NodeHandleId } from '../../constant';
|
import { NodeHandleId } from '../../constant';
|
||||||
|
import useGraphStore from '../../store';
|
||||||
import { NodeWrapper } from './node-wrapper';
|
import { NodeWrapper } from './node-wrapper';
|
||||||
|
|
||||||
function InnerToolNode({
|
function InnerToolNode({
|
||||||
@ -10,6 +12,16 @@ function InnerToolNode({
|
|||||||
isConnectable = true,
|
isConnectable = true,
|
||||||
selected,
|
selected,
|
||||||
}: NodeProps<IToolNode>) {
|
}: NodeProps<IToolNode>) {
|
||||||
|
const { edges, getNode } = useGraphStore((state) => state);
|
||||||
|
const upstreamAgentNodeId = edges.find((x) => x.target === id)?.source;
|
||||||
|
const upstreamAgentNode = getNode(upstreamAgentNodeId);
|
||||||
|
|
||||||
|
const tools: IAgentForm['tools'] = get(
|
||||||
|
upstreamAgentNode,
|
||||||
|
'data.form.tools',
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeWrapper>
|
<NodeWrapper>
|
||||||
<Handle
|
<Handle
|
||||||
@ -18,6 +30,11 @@ function InnerToolNode({
|
|||||||
position={Position.Top}
|
position={Position.Top}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
></Handle>
|
></Handle>
|
||||||
|
<ul className="space-y-1">
|
||||||
|
{tools.map((x) => (
|
||||||
|
<li key={x.component_name}>{x.component_name}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
</NodeWrapper>
|
</NodeWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import RetrievalForm from '../form/retrieval-form/next';
|
|||||||
import RewriteQuestionForm from '../form/rewrite-question-form';
|
import RewriteQuestionForm from '../form/rewrite-question-form';
|
||||||
import SwitchForm from '../form/switch-form';
|
import SwitchForm from '../form/switch-form';
|
||||||
import TemplateForm from '../form/template-form';
|
import TemplateForm from '../form/template-form';
|
||||||
|
import ToolForm from '../form/tool-form';
|
||||||
import TuShareForm from '../form/tushare-form';
|
import TuShareForm from '../form/tushare-form';
|
||||||
import WenCaiForm from '../form/wencai-form';
|
import WenCaiForm from '../form/wencai-form';
|
||||||
import WikipediaForm from '../form/wikipedia-form';
|
import WikipediaForm from '../form/wikipedia-form';
|
||||||
@ -369,6 +370,11 @@ export function useFormConfigMap() {
|
|||||||
defaultValues: {},
|
defaultValues: {},
|
||||||
schema: z.object({}),
|
schema: z.object({}),
|
||||||
},
|
},
|
||||||
|
[Operator.Tool]: {
|
||||||
|
component: ToolForm,
|
||||||
|
defaultValues: {},
|
||||||
|
schema: z.object({}),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return FormConfigMap;
|
return FormConfigMap;
|
||||||
|
|||||||
@ -3,33 +3,43 @@ import {
|
|||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from '@/components/ui/popover';
|
} from '@/components/ui/popover';
|
||||||
|
import { IAgentForm } from '@/interfaces/database/agent';
|
||||||
import { Operator } from '@/pages/agent/constant';
|
import { Operator } from '@/pages/agent/constant';
|
||||||
import { AgentFormContext, AgentInstanceContext } from '@/pages/agent/context';
|
import { AgentFormContext, AgentInstanceContext } from '@/pages/agent/context';
|
||||||
import { Position } from '@xyflow/react';
|
import { Position } from '@xyflow/react';
|
||||||
import { PropsWithChildren, useCallback, useContext } from 'react';
|
import { get } from 'lodash';
|
||||||
|
import { PropsWithChildren, useCallback, useContext, useMemo } from 'react';
|
||||||
import { ToolCommand } from './tool-command';
|
import { ToolCommand } from './tool-command';
|
||||||
|
import { useUpdateAgentNodeTools } from './use-update-tools';
|
||||||
|
|
||||||
export function ToolPopover({ children }: PropsWithChildren) {
|
export function ToolPopover({ children }: PropsWithChildren) {
|
||||||
const { addCanvasNode } = useContext(AgentInstanceContext);
|
const { addCanvasNode } = useContext(AgentInstanceContext);
|
||||||
const node = useContext(AgentFormContext);
|
const node = useContext(AgentFormContext);
|
||||||
|
const { updateNodeTools } = useUpdateAgentNodeTools();
|
||||||
|
|
||||||
|
const toolNames = useMemo(() => {
|
||||||
|
const tools: IAgentForm['tools'] = get(node, 'data.form.tools', []);
|
||||||
|
return tools.map((x) => x.component_name);
|
||||||
|
}, [node]);
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(value: string[]) => {
|
(value: string[]) => {
|
||||||
if (Array.isArray(value) && value.length > 0) {
|
if (Array.isArray(value) && value.length > 0 && node?.id) {
|
||||||
|
updateNodeTools(value);
|
||||||
addCanvasNode(Operator.Tool, {
|
addCanvasNode(Operator.Tool, {
|
||||||
position: Position.Bottom,
|
position: Position.Bottom,
|
||||||
nodeId: node?.id,
|
nodeId: node?.id,
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[addCanvasNode, node?.id],
|
[addCanvasNode, node?.id, updateNodeTools],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
||||||
<PopoverContent className="w-80 p-0">
|
<PopoverContent className="w-80 p-0">
|
||||||
<ToolCommand onChange={handleChange}></ToolCommand>
|
<ToolCommand onChange={handleChange} value={toolNames}></ToolCommand>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -45,11 +45,6 @@ const Menus = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const Options = Menus.reduce<string[]>((pre, cur) => {
|
|
||||||
pre.push(...cur.list);
|
|
||||||
return pre;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
type ToolCommandProps = {
|
type ToolCommandProps = {
|
||||||
value?: string[];
|
value?: string[];
|
||||||
onChange?(values: string[]): void;
|
onChange?(values: string[]): void;
|
||||||
@ -57,7 +52,6 @@ type ToolCommandProps = {
|
|||||||
|
|
||||||
export function ToolCommand({ value, onChange }: ToolCommandProps) {
|
export function ToolCommand({ value, onChange }: ToolCommandProps) {
|
||||||
const [currentValue, setCurrentValue] = useState<string[]>([]);
|
const [currentValue, setCurrentValue] = useState<string[]>([]);
|
||||||
console.log('🚀 ~ ToolCommand ~ currentValue:', currentValue);
|
|
||||||
|
|
||||||
const toggleOption = useCallback(
|
const toggleOption = useCallback(
|
||||||
(option: string) => {
|
(option: string) => {
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { IAgentForm } from '@/interfaces/database/agent';
|
||||||
|
import { AgentFormContext } from '@/pages/agent/context';
|
||||||
|
import useGraphStore from '@/pages/agent/store';
|
||||||
|
import { get } from 'lodash';
|
||||||
|
import { useCallback, useContext } from 'react';
|
||||||
|
|
||||||
|
export function useUpdateAgentNodeTools() {
|
||||||
|
const { updateNodeForm } = useGraphStore((state) => state);
|
||||||
|
const node = useContext(AgentFormContext);
|
||||||
|
|
||||||
|
const updateNodeTools = useCallback(
|
||||||
|
(value: string[]) => {
|
||||||
|
if (node?.id) {
|
||||||
|
const tools: IAgentForm['tools'] = get(node, 'data.form.tools');
|
||||||
|
|
||||||
|
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: {} });
|
||||||
|
return pre;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
updateNodeForm(node?.id, nextValue, ['tools']);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[node, updateNodeForm],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { updateNodeTools };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user