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_goto: any;
|
||||
tools: Array<{
|
||||
name: string;
|
||||
component_name: string;
|
||||
params: Record<string, any>;
|
||||
}>;
|
||||
|
||||
@ -14,7 +14,7 @@ import { Play, X } from 'lucide-react';
|
||||
import { BeginId, Operator } from '../constant';
|
||||
import { AgentFormContext } from '../context';
|
||||
import { RunTooltip } from '../flow-tooltip';
|
||||
import { useHandleNodeNameChange } from '../hooks';
|
||||
import { useHandleNodeNameChange } from '../hooks/use-change-node-name';
|
||||
import OperatorIcon from '../operator-icon';
|
||||
import { needsSingleStepDebugging } from '../utils';
|
||||
import SingleDebugDrawer from './single-debug-drawer';
|
||||
|
||||
@ -29,6 +29,7 @@ export function useUpdateAgentNodeTools() {
|
||||
? tool
|
||||
: {
|
||||
component_name: cur,
|
||||
name: cur,
|
||||
params:
|
||||
DefaultAgentToolValuesMap[
|
||||
cur as keyof typeof DefaultAgentToolValuesMap
|
||||
|
||||
@ -5,34 +5,19 @@ import {
|
||||
Position,
|
||||
ReactFlowInstance,
|
||||
} from '@xyflow/react';
|
||||
import React, {
|
||||
ChangeEvent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
// import { shallow } from 'zustand/shallow';
|
||||
import { settledModelVariableMap } from '@/constants/knowledge';
|
||||
import { useFetchModelId } from '@/hooks/logic-hooks';
|
||||
import { ISwitchForm } from '@/interfaces/database/agent';
|
||||
import {
|
||||
ICategorizeForm,
|
||||
IRelevantForm,
|
||||
RAGFlowNodeType,
|
||||
} from '@/interfaces/database/flow';
|
||||
import { message } from 'antd';
|
||||
import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
||||
import { humanId } from 'human-id';
|
||||
import { get, lowerFirst, omit } from 'lodash';
|
||||
import trim from 'lodash/trim';
|
||||
import { UseFormReturn } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import {
|
||||
NodeMap,
|
||||
Operator,
|
||||
RestrictedUpstreamMap,
|
||||
SwitchElseTo,
|
||||
initialAgentValues,
|
||||
initialAkShareValues,
|
||||
initialArXivValues,
|
||||
@ -76,7 +61,6 @@ import useGraphStore, { RFState } from './store';
|
||||
import {
|
||||
buildCategorizeObjectFromList,
|
||||
generateNodeNamesWithIncreasingIndex,
|
||||
generateSwitchHandleText,
|
||||
getNodeDragHandle,
|
||||
getRelativePositionToIterationNode,
|
||||
replaceIdWithText,
|
||||
@ -389,43 +373,6 @@ export const useValidateConnection = () => {
|
||||
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 = () => {
|
||||
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 = () => {
|
||||
const duplicateNodeById = useGraphStore((store) => store.duplicateNode);
|
||||
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