diff --git a/web/src/pages/agent/canvas/index.tsx b/web/src/pages/agent/canvas/index.tsx index e19a90782..41495ce28 100644 --- a/web/src/pages/agent/canvas/index.tsx +++ b/web/src/pages/agent/canvas/index.tsx @@ -116,6 +116,7 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) { runVisible, hideRunOrChatDrawer, showChatModal, + showFormDrawer, } = useShowDrawer({ drawerVisible, hideDrawer, @@ -175,7 +176,7 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) { - + {formDrawerVisible && ( - + ( undefined, @@ -12,7 +12,8 @@ export const AgentFormContext = createContext( type AgentInstanceContextType = Pick< ReturnType, 'addCanvasNode' ->; +> & + Pick, 'showFormDrawer'>; export const AgentInstanceContext = createContext( {} as AgentInstanceContextType, diff --git a/web/src/pages/agent/form/agent-form/agent-tools.tsx b/web/src/pages/agent/form/agent-form/agent-tools.tsx index 09e1c23a5..507eaa947 100644 --- a/web/src/pages/agent/form/agent-form/agent-tools.tsx +++ b/web/src/pages/agent/form/agent-form/agent-tools.tsx @@ -2,7 +2,13 @@ import { BlockButton } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import { Position } from '@xyflow/react'; import { PencilLine, X } from 'lucide-react'; -import { PropsWithChildren, useCallback, useContext, useMemo } from 'react'; +import { + MouseEventHandler, + PropsWithChildren, + useCallback, + useContext, + useMemo, +} from 'react'; import { Operator } from '../../constant'; import { AgentInstanceContext } from '../../context'; import { useFindMcpById } from '../../hooks/use-find-mcp-by-id'; @@ -35,23 +41,20 @@ export function ToolCard({ type ActionButtonProps = { record: T; deleteRecord(record: T): void; - edit(record: T): void; + edit: MouseEventHandler; }; -function ActionButton({ edit, deleteRecord, record }: ActionButtonProps) { +function ActionButton({ deleteRecord, record, edit }: ActionButtonProps) { const handleDelete = useCallback(() => { deleteRecord(record); }, [deleteRecord, record]); - const handleEdit = useCallback(() => { - edit(record); - }, [edit, record]); return (
@@ -64,6 +67,21 @@ export function AgentTools() { const { mcpIds } = useGetAgentMCPIds(); const { findMcpById } = useFindMcpById(); const { deleteNodeMCP } = useDeleteAgentNodeMCP(); + const { showFormDrawer } = useContext(AgentInstanceContext); + const { clickedNodeId, findAgentToolNodeById, selectNodeIds } = useGraphStore( + (state) => state, + ); + + const handleEdit: MouseEventHandler = useCallback( + (e) => { + const toolNodeId = findAgentToolNodeById(clickedNodeId); + if (toolNodeId) { + selectNodeIds([toolNodeId]); + showFormDrawer(e, toolNodeId); + } + }, + [clickedNodeId, findAgentToolNodeById, selectNodeIds, showFormDrawer], + ); return (
@@ -74,8 +92,8 @@ export function AgentTools() { {x} {}} deleteRecord={deleteNodeTool(x)} + edit={handleEdit} > ))} @@ -84,8 +102,8 @@ export function AgentTools() { {findMcpById(id)?.name} {}} deleteRecord={deleteNodeMCP(id)} + edit={handleEdit} > ))} @@ -99,8 +117,17 @@ export function AgentTools() { export function Agents({ node }: INextOperatorForm) { const { addCanvasNode } = useContext(AgentInstanceContext); - const { deleteAgentDownstreamNodesById, edges, getNode } = useGraphStore( - (state) => state, + const { deleteAgentDownstreamNodesById, edges, getNode, selectNodeIds } = + useGraphStore((state) => state); + const { showFormDrawer } = useContext(AgentInstanceContext); + + const handleEdit = useCallback( + (nodeId: string): MouseEventHandler => + (e) => { + selectNodeIds([nodeId]); + showFormDrawer(e, nodeId); + }, + [selectNodeIds, showFormDrawer], ); const subBottomAgentNodeIds = useMemo(() => { @@ -119,8 +146,8 @@ export function Agents({ node }: INextOperatorForm) { {currentNode?.data.name} {}} deleteRecord={deleteAgentDownstreamNodesById} + edit={handleEdit(id)} > ); diff --git a/web/src/pages/agent/form/agent-form/tool-popover/use-update-mcp.ts b/web/src/pages/agent/form/agent-form/tool-popover/use-update-mcp.ts index dbb3e5b54..827b9f9e1 100644 --- a/web/src/pages/agent/form/agent-form/tool-popover/use-update-mcp.ts +++ b/web/src/pages/agent/form/agent-form/tool-popover/use-update-mcp.ts @@ -40,7 +40,7 @@ export function useUpdateAgentNodeMCP() { } else if (tools) { pre.push({ mcp_id: cur, - tools, + tools: {}, }); } return pre; diff --git a/web/src/pages/agent/hooks/use-show-drawer.tsx b/web/src/pages/agent/hooks/use-show-drawer.tsx index a0e553c15..268697ed6 100644 --- a/web/src/pages/agent/hooks/use-show-drawer.tsx +++ b/web/src/pages/agent/hooks/use-show-drawer.tsx @@ -1,7 +1,7 @@ import { useSetModalState } from '@/hooks/common-hooks'; -import { Node, NodeMouseHandler } from '@xyflow/react'; +import { NodeMouseHandler } from '@xyflow/react'; import get from 'lodash/get'; -import { useCallback, useEffect } from 'react'; +import React, { useCallback, useEffect } from 'react'; import { Operator } from '../constant'; import useGraphStore from '../store'; import { useCacheChatLog } from './use-cache-chat-log'; @@ -21,9 +21,9 @@ export const useShowFormDrawer = () => { showModal: showFormDrawer, } = useSetModalState(); - const handleShow: NodeMouseHandler = useCallback( - (e, node: Node) => { - setClickedNodeId(node.id); + const handleShow = useCallback( + (e: React.MouseEvent, nodeId: string) => { + setClickedNodeId(nodeId); setClickedToolId(get(e.target, 'dataset.tool')); showFormDrawer(); }, @@ -118,7 +118,7 @@ export function useShowDrawer({ if (!ExcludedNodes.some((x) => x === node.data.label)) { hideSingleDebugDrawer(); // hideRunOrChatDrawer(); - showFormDrawer(e, node); + showFormDrawer(e, node.id); } // handle single debug icon click if ( diff --git a/web/src/pages/agent/store.ts b/web/src/pages/agent/store.ts index d52bff641..66d29edbe 100644 --- a/web/src/pages/agent/store.ts +++ b/web/src/pages/agent/store.ts @@ -85,6 +85,8 @@ export type RFState = { setClickedToolId: (id?: string) => void; findUpstreamNodeById: (id?: string | null) => RAGFlowNodeType | undefined; deleteCategorizeCaseEdges: (source: string, sourceHandle: string) => void; // Deleting a condition of a classification operator will delete the related edge + findAgentToolNodeById: (id: string | null) => string | undefined; + selectNodeIds: (nodeIds: string[]) => void; }; // this is our useStore hook that we can use in our components to get parts of the store and call actions @@ -518,6 +520,22 @@ const useGraphStore = create()( ), ); }, + findAgentToolNodeById: (id) => { + const { edges } = get(); + return edges.find( + (edge) => + edge.source === id && edge.sourceHandle === NodeHandleId.Tool, + )?.target; + }, + selectNodeIds: (nodeIds) => { + const { nodes, setNodes } = get(); + setNodes( + nodes.map((node) => ({ + ...node, + selected: nodeIds.includes(node.id), + })), + ); + }, })), { name: 'graph', trace: true }, ),