Bläddra i källkod

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)
tags/v0.20.0
balibabu 3 månader sedan
förälder
incheckning
98829f5dbe
Inget konto är kopplat till bidragsgivarens mejladress

+ 1
- 0
web/src/interfaces/database/agent.ts Visa fil

@@ -155,6 +155,7 @@ export interface IAgentForm {
exception_comment: any;
exception_goto: any;
tools: Array<{
name: string;
component_name: string;
params: Record<string, any>;
}>;

+ 1
- 1
web/src/pages/agent/form-sheet/next.tsx Visa fil

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

+ 1
- 0
web/src/pages/agent/form/agent-form/tool-popover/use-update-tools.ts Visa fil

@@ -29,6 +29,7 @@ export function useUpdateAgentNodeTools() {
? tool
: {
component_name: cur,
name: cur,
params:
DefaultAgentToolValuesMap[
cur as keyof typeof DefaultAgentToolValuesMap

+ 2
- 169
web/src/pages/agent/hooks.tsx Visa fil

@@ -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
- 0
web/src/pages/agent/hooks/use-change-node-name.ts Visa fil

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

Laddar…
Avbryt
Spara