Feat: Limit the appearance of loops in operators in the agent canvas #3221 (#9253)

### What problem does this PR solve?
Feat: Limit the appearance of loops in operators in the agent canvas
#3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-08-05 19:21:24 +08:00
committed by GitHub
parent f235a38225
commit ed9757b0c7
2 changed files with 32 additions and 10 deletions

View File

@ -843,7 +843,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
relevant: '是否相关', relevant: '是否相关',
rewriteQuestion: '问题优化', rewriteQuestion: '问题优化',
begin: '开始', begin: '开始',
message: '静态消息', message: '回复消息',
blank: '空', blank: '空',
createFromNothing: '从无到有', createFromNothing: '从无到有',
addItem: '新增', addItem: '新增',
@ -1245,7 +1245,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
modeTip: '模式定义了工作流的启动方式。', modeTip: '模式定义了工作流的启动方式。',
beginInputTip: '通过定义输入参数,此内容可以被后续流程中的其他组件访问。', beginInputTip: '通过定义输入参数,此内容可以被后续流程中的其他组件访问。',
query: '查询变量', query: '查询变量',
agent: 'Agent', agent: '智能体',
agentDescription: '构建具备推理、工具调用和多智能体协同的智能体组件。', agentDescription: '构建具备推理、工具调用和多智能体协同的智能体组件。',
maxRecords: '最大记录数', maxRecords: '最大记录数',
createAgent: 'Create Agent', createAgent: 'Create Agent',

View File

@ -1,6 +1,7 @@
import { import {
Connection, Connection,
Edge, Edge,
getOutgoers,
Node, Node,
Position, Position,
ReactFlowInstance, ReactFlowInstance,
@ -15,9 +16,6 @@ import { get, lowerFirst, omit } from 'lodash';
import { UseFormReturn } from 'react-hook-form'; import { UseFormReturn } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
NodeMap,
Operator,
RestrictedUpstreamMap,
initialAgentValues, initialAgentValues,
initialAkShareValues, initialAkShareValues,
initialArXivValues, initialArXivValues,
@ -57,6 +55,9 @@ import {
initialWenCaiValues, initialWenCaiValues,
initialWikipediaValues, initialWikipediaValues,
initialYahooFinanceValues, initialYahooFinanceValues,
NodeMap,
Operator,
RestrictedUpstreamMap,
} from './constant'; } from './constant';
import useGraphStore, { RFState } from './store'; import useGraphStore, { RFState } from './store';
import { import {
@ -333,9 +334,8 @@ export const useHandleFormValuesChange = (
}; };
export const useValidateConnection = () => { export const useValidateConnection = () => {
const { getOperatorTypeFromId, getParentIdById } = useGraphStore( const { getOperatorTypeFromId, getParentIdById, edges, nodes } =
(state) => state, useGraphStore((state) => state);
);
const isSameNodeChild = useCallback( const isSameNodeChild = useCallback(
(connection: Connection | Edge) => { (connection: Connection | Edge) => {
@ -349,6 +349,27 @@ export const useValidateConnection = () => {
[getParentIdById], [getParentIdById],
); );
const hasCanvasCycle = useCallback(
(connection: Connection | Edge) => {
const target = nodes.find((node) => node.id === connection.target);
const hasCycle = (node: RAGFlowNodeType, visited = new Set()) => {
if (visited.has(node.id)) return false;
visited.add(node.id);
for (const outgoer of getOutgoers(node, nodes, edges)) {
if (outgoer.id === connection.source) return true;
if (hasCycle(outgoer, visited)) return true;
}
};
if (target?.id === connection.source) return false;
return target ? !hasCycle(target) : false;
},
[edges, nodes],
);
// restricted lines cannot be connected successfully. // restricted lines cannot be connected successfully.
const isValidConnection = useCallback( const isValidConnection = useCallback(
(connection: Connection | Edge) => { (connection: Connection | Edge) => {
@ -365,10 +386,11 @@ export const useValidateConnection = () => {
RestrictedUpstreamMap[ RestrictedUpstreamMap[
getOperatorTypeFromId(connection.source) as Operator getOperatorTypeFromId(connection.source) as Operator
]?.every((x) => x !== getOperatorTypeFromId(connection.target)) && ]?.every((x) => x !== getOperatorTypeFromId(connection.target)) &&
isSameNodeChild(connection); isSameNodeChild(connection) &&
hasCanvasCycle(connection);
return ret; return ret;
}, },
[getOperatorTypeFromId, isSameNodeChild], [getOperatorTypeFromId, hasCanvasCycle, isSameNodeChild],
); );
return isValidConnection; return isValidConnection;