Feat: Modify the agent tool name #3221 (#8780)

### 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:
balibabu
2025-07-10 18:36:34 +08:00
committed by GitHub
parent 512772c45a
commit 98829f5dbe
5 changed files with 125 additions and 170 deletions

View File

@ -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>;
}>; }>;

View File

@ -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';

View File

@ -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

View File

@ -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();

View 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,
};
};