mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Modify the agent tool name #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -155,6 +155,7 @@ export interface IAgentForm {
|
|||||||
exception_comment: any;
|
exception_comment: any;
|
||||||
exception_goto: any;
|
exception_goto: any;
|
||||||
tools: Array<{
|
tools: Array<{
|
||||||
|
name: string;
|
||||||
component_name: string;
|
component_name: string;
|
||||||
params: Record<string, any>;
|
params: Record<string, any>;
|
||||||
}>;
|
}>;
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { Play, X } from 'lucide-react';
|
|||||||
import { BeginId, Operator } from '../constant';
|
import { BeginId, Operator } from '../constant';
|
||||||
import { AgentFormContext } from '../context';
|
import { AgentFormContext } from '../context';
|
||||||
import { RunTooltip } from '../flow-tooltip';
|
import { RunTooltip } from '../flow-tooltip';
|
||||||
import { useHandleNodeNameChange } from '../hooks';
|
import { useHandleNodeNameChange } from '../hooks/use-change-node-name';
|
||||||
import OperatorIcon from '../operator-icon';
|
import OperatorIcon from '../operator-icon';
|
||||||
import { needsSingleStepDebugging } from '../utils';
|
import { needsSingleStepDebugging } from '../utils';
|
||||||
import SingleDebugDrawer from './single-debug-drawer';
|
import SingleDebugDrawer from './single-debug-drawer';
|
||||||
|
|||||||
@ -29,6 +29,7 @@ export function useUpdateAgentNodeTools() {
|
|||||||
? tool
|
? tool
|
||||||
: {
|
: {
|
||||||
component_name: cur,
|
component_name: cur,
|
||||||
|
name: cur,
|
||||||
params:
|
params:
|
||||||
DefaultAgentToolValuesMap[
|
DefaultAgentToolValuesMap[
|
||||||
cur as keyof typeof DefaultAgentToolValuesMap
|
cur as keyof typeof DefaultAgentToolValuesMap
|
||||||
|
|||||||
@ -5,34 +5,19 @@ import {
|
|||||||
Position,
|
Position,
|
||||||
ReactFlowInstance,
|
ReactFlowInstance,
|
||||||
} from '@xyflow/react';
|
} from '@xyflow/react';
|
||||||
import React, {
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
ChangeEvent,
|
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
// import { shallow } from 'zustand/shallow';
|
// import { shallow } from 'zustand/shallow';
|
||||||
import { settledModelVariableMap } from '@/constants/knowledge';
|
import { settledModelVariableMap } from '@/constants/knowledge';
|
||||||
import { useFetchModelId } from '@/hooks/logic-hooks';
|
import { useFetchModelId } from '@/hooks/logic-hooks';
|
||||||
import { ISwitchForm } from '@/interfaces/database/agent';
|
import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
||||||
import {
|
|
||||||
ICategorizeForm,
|
|
||||||
IRelevantForm,
|
|
||||||
RAGFlowNodeType,
|
|
||||||
} from '@/interfaces/database/flow';
|
|
||||||
import { message } from 'antd';
|
|
||||||
import { humanId } from 'human-id';
|
import { humanId } from 'human-id';
|
||||||
import { get, lowerFirst, omit } from 'lodash';
|
import { get, lowerFirst, omit } from 'lodash';
|
||||||
import trim from 'lodash/trim';
|
|
||||||
import { UseFormReturn } from 'react-hook-form';
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
import {
|
import {
|
||||||
NodeMap,
|
NodeMap,
|
||||||
Operator,
|
Operator,
|
||||||
RestrictedUpstreamMap,
|
RestrictedUpstreamMap,
|
||||||
SwitchElseTo,
|
|
||||||
initialAgentValues,
|
initialAgentValues,
|
||||||
initialAkShareValues,
|
initialAkShareValues,
|
||||||
initialArXivValues,
|
initialArXivValues,
|
||||||
@ -76,7 +61,6 @@ import useGraphStore, { RFState } from './store';
|
|||||||
import {
|
import {
|
||||||
buildCategorizeObjectFromList,
|
buildCategorizeObjectFromList,
|
||||||
generateNodeNamesWithIncreasingIndex,
|
generateNodeNamesWithIncreasingIndex,
|
||||||
generateSwitchHandleText,
|
|
||||||
getNodeDragHandle,
|
getNodeDragHandle,
|
||||||
getRelativePositionToIterationNode,
|
getRelativePositionToIterationNode,
|
||||||
replaceIdWithText,
|
replaceIdWithText,
|
||||||
@ -389,43 +373,6 @@ export const useValidateConnection = () => {
|
|||||||
return isValidConnection;
|
return isValidConnection;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useHandleNodeNameChange = ({
|
|
||||||
id,
|
|
||||||
data,
|
|
||||||
}: {
|
|
||||||
id?: string;
|
|
||||||
data: any;
|
|
||||||
}) => {
|
|
||||||
const [name, setName] = useState<string>('');
|
|
||||||
const { updateNodeName, nodes } = useGraphStore((state) => state);
|
|
||||||
const previousName = data?.name;
|
|
||||||
|
|
||||||
const handleNameBlur = useCallback(() => {
|
|
||||||
const existsSameName = nodes.some((x) => x.data.name === name);
|
|
||||||
if (trim(name) === '' || existsSameName) {
|
|
||||||
if (existsSameName && previousName !== name) {
|
|
||||||
message.error('The name cannot be repeated');
|
|
||||||
}
|
|
||||||
setName(previousName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id) {
|
|
||||||
updateNodeName(id, name);
|
|
||||||
}
|
|
||||||
}, [name, id, updateNodeName, previousName, nodes]);
|
|
||||||
|
|
||||||
const handleNameChange = useCallback((e: ChangeEvent<any>) => {
|
|
||||||
setName(e.target.value);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setName(previousName);
|
|
||||||
}, [previousName]);
|
|
||||||
|
|
||||||
return { name, handleNameBlur, handleNameChange };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useReplaceIdWithName = () => {
|
export const useReplaceIdWithName = () => {
|
||||||
const getNode = useGraphStore((state) => state.getNode);
|
const getNode = useGraphStore((state) => state.getNode);
|
||||||
|
|
||||||
@ -448,120 +395,6 @@ export const useReplaceIdWithText = (output: unknown) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* monitor changes in the data.form field of the categorize and relevant operators
|
|
||||||
* and then synchronize them to the edge
|
|
||||||
*/
|
|
||||||
export const useWatchNodeFormDataChange = () => {
|
|
||||||
const { getNode, nodes, setEdgesByNodeId } = useGraphStore((state) => state);
|
|
||||||
|
|
||||||
const buildCategorizeEdgesByFormData = useCallback(
|
|
||||||
(nodeId: string, form: ICategorizeForm) => {
|
|
||||||
// add
|
|
||||||
// delete
|
|
||||||
// edit
|
|
||||||
const categoryDescription = form.category_description;
|
|
||||||
const downstreamEdges = Object.keys(categoryDescription).reduce<Edge[]>(
|
|
||||||
(pre, sourceHandle) => {
|
|
||||||
const target = categoryDescription[sourceHandle]?.to;
|
|
||||||
if (target) {
|
|
||||||
pre.push({
|
|
||||||
id: uuid(),
|
|
||||||
source: nodeId,
|
|
||||||
target,
|
|
||||||
sourceHandle,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return pre;
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
setEdgesByNodeId(nodeId, downstreamEdges);
|
|
||||||
},
|
|
||||||
[setEdgesByNodeId],
|
|
||||||
);
|
|
||||||
|
|
||||||
const buildRelevantEdgesByFormData = useCallback(
|
|
||||||
(nodeId: string, form: IRelevantForm) => {
|
|
||||||
const downstreamEdges = ['yes', 'no'].reduce<Edge[]>((pre, cur) => {
|
|
||||||
const target = form[cur as keyof IRelevantForm] as string;
|
|
||||||
if (target) {
|
|
||||||
pre.push({ id: uuid(), source: nodeId, target, sourceHandle: cur });
|
|
||||||
}
|
|
||||||
|
|
||||||
return pre;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
setEdgesByNodeId(nodeId, downstreamEdges);
|
|
||||||
},
|
|
||||||
[setEdgesByNodeId],
|
|
||||||
);
|
|
||||||
|
|
||||||
const buildSwitchEdgesByFormData = useCallback(
|
|
||||||
(nodeId: string, form: ISwitchForm) => {
|
|
||||||
// add
|
|
||||||
// delete
|
|
||||||
// edit
|
|
||||||
const conditions = form.conditions;
|
|
||||||
const downstreamEdges = conditions.reduce<Edge[]>((pre, _, idx) => {
|
|
||||||
const target = conditions[idx]?.to;
|
|
||||||
if (target) {
|
|
||||||
pre.push({
|
|
||||||
id: uuid(),
|
|
||||||
source: nodeId,
|
|
||||||
target,
|
|
||||||
sourceHandle: generateSwitchHandleText(idx),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return pre;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Splice the else condition of the conditional judgment to the edge list
|
|
||||||
const elseTo = form[SwitchElseTo];
|
|
||||||
if (elseTo) {
|
|
||||||
downstreamEdges.push({
|
|
||||||
id: uuid(),
|
|
||||||
source: nodeId,
|
|
||||||
target: elseTo,
|
|
||||||
sourceHandle: SwitchElseTo,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setEdgesByNodeId(nodeId, downstreamEdges);
|
|
||||||
},
|
|
||||||
[setEdgesByNodeId],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
nodes.forEach((node) => {
|
|
||||||
const currentNode = getNode(node.id);
|
|
||||||
const form = currentNode?.data.form ?? {};
|
|
||||||
const operatorType = currentNode?.data.label;
|
|
||||||
switch (operatorType) {
|
|
||||||
case Operator.Relevant:
|
|
||||||
buildRelevantEdgesByFormData(node.id, form as IRelevantForm);
|
|
||||||
break;
|
|
||||||
case Operator.Categorize:
|
|
||||||
buildCategorizeEdgesByFormData(node.id, form as ICategorizeForm);
|
|
||||||
break;
|
|
||||||
// case Operator.Switch:
|
|
||||||
// buildSwitchEdgesByFormData(node.id, form as ISwitchForm);
|
|
||||||
// break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [
|
|
||||||
nodes,
|
|
||||||
buildCategorizeEdgesByFormData,
|
|
||||||
getNode,
|
|
||||||
buildRelevantEdgesByFormData,
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useDuplicateNode = () => {
|
export const useDuplicateNode = () => {
|
||||||
const duplicateNodeById = useGraphStore((store) => store.duplicateNode);
|
const duplicateNodeById = useGraphStore((store) => store.duplicateNode);
|
||||||
const getNodeName = useGetNodeName();
|
const getNodeName = useGetNodeName();
|
||||||
|
|||||||
120
web/src/pages/agent/hooks/use-change-node-name.ts
Normal file
120
web/src/pages/agent/hooks/use-change-node-name.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import message from '@/components/ui/message';
|
||||||
|
import { trim } from 'lodash';
|
||||||
|
import {
|
||||||
|
ChangeEvent,
|
||||||
|
Dispatch,
|
||||||
|
SetStateAction,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
import { Operator } from '../constant';
|
||||||
|
import useGraphStore from '../store';
|
||||||
|
import { getAgentNodeTools } from '../utils';
|
||||||
|
|
||||||
|
export function useHandleTooNodeNameChange({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
setName,
|
||||||
|
}: {
|
||||||
|
id?: string;
|
||||||
|
name?: string;
|
||||||
|
setName: Dispatch<SetStateAction<string>>;
|
||||||
|
}) {
|
||||||
|
const { clickedToolId, findUpstreamNodeById, updateNodeForm } = useGraphStore(
|
||||||
|
(state) => state,
|
||||||
|
);
|
||||||
|
const agentNode = findUpstreamNodeById(id);
|
||||||
|
const tools = getAgentNodeTools(agentNode);
|
||||||
|
|
||||||
|
const previousName = useMemo(() => {
|
||||||
|
const tool = tools.find((x) => x.component_name === clickedToolId);
|
||||||
|
return tool?.name || tool?.component_name;
|
||||||
|
}, [clickedToolId, tools]);
|
||||||
|
|
||||||
|
const handleToolNameBlur = useCallback(() => {
|
||||||
|
const trimmedName = trim(name);
|
||||||
|
const existsSameName = tools.some((x) => x.name === trimmedName);
|
||||||
|
if (trimmedName === '' || existsSameName) {
|
||||||
|
if (existsSameName && previousName !== name) {
|
||||||
|
message.error('The name cannot be repeated');
|
||||||
|
}
|
||||||
|
setName(previousName || '');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (agentNode?.id) {
|
||||||
|
const nextTools = tools.map((x) => {
|
||||||
|
if (x.component_name === clickedToolId) {
|
||||||
|
return {
|
||||||
|
...x,
|
||||||
|
name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
});
|
||||||
|
updateNodeForm(agentNode?.id, nextTools, ['tools']);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
agentNode?.id,
|
||||||
|
clickedToolId,
|
||||||
|
name,
|
||||||
|
previousName,
|
||||||
|
setName,
|
||||||
|
tools,
|
||||||
|
updateNodeForm,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return { handleToolNameBlur, previousToolName: previousName };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useHandleNodeNameChange = ({
|
||||||
|
id,
|
||||||
|
data,
|
||||||
|
}: {
|
||||||
|
id?: string;
|
||||||
|
data: any;
|
||||||
|
}) => {
|
||||||
|
const [name, setName] = useState<string>('');
|
||||||
|
const { updateNodeName, nodes, getOperatorTypeFromId } = useGraphStore(
|
||||||
|
(state) => state,
|
||||||
|
);
|
||||||
|
const previousName = data?.name;
|
||||||
|
const isToolNode = getOperatorTypeFromId(id) === Operator.Tool;
|
||||||
|
|
||||||
|
const { handleToolNameBlur, previousToolName } = useHandleTooNodeNameChange({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
setName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleNameBlur = useCallback(() => {
|
||||||
|
const existsSameName = nodes.some((x) => x.data.name === name);
|
||||||
|
if (trim(name) === '' || existsSameName) {
|
||||||
|
if (existsSameName && previousName !== name) {
|
||||||
|
message.error('The name cannot be repeated');
|
||||||
|
}
|
||||||
|
setName(previousName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
updateNodeName(id, name);
|
||||||
|
}
|
||||||
|
}, [name, id, updateNodeName, previousName, nodes]);
|
||||||
|
|
||||||
|
const handleNameChange = useCallback((e: ChangeEvent<any>) => {
|
||||||
|
setName(e.target.value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setName(isToolNode ? previousToolName : previousName);
|
||||||
|
}, [isToolNode, previousName, previousToolName]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
handleNameBlur: isToolNode ? handleToolNameBlur : handleNameBlur,
|
||||||
|
handleNameChange,
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user