From 4fa29f3bee07b492d0fdb4875ab9e48b925615ae Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 4 Mar 2026 16:06:13 +0800 Subject: [PATCH] feat(agent): add GNS3ProjectInfoTool to gns3_client exports Add GNS3ProjectInfoTool to the __all__ list in gns3_client/__init__.py to make it available for import. This ensures the tool is properly exposed as part of the public API for use in copilot agent modules. --- .../gns3_copilot/gns3_client/__init__.py | 2 + .../gns3_client/gns3_project_info.py | 126 ++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 gns3server/agent/gns3_copilot/gns3_client/gns3_project_info.py diff --git a/gns3server/agent/gns3_copilot/gns3_client/__init__.py b/gns3server/agent/gns3_copilot/gns3_client/__init__.py index 0ffa69c1d..246940e56 100644 --- a/gns3server/agent/gns3_copilot/gns3_client/__init__.py +++ b/gns3server/agent/gns3_copilot/gns3_client/__init__.py @@ -40,6 +40,7 @@ from .custom_gns3fy import ( Project, ) from .gns3_topology_reader import GNS3TopologyTool +from .gns3_project_info import GNS3ProjectInfoTool # Dynamic version management try: @@ -62,6 +63,7 @@ __all__ = [ "CONSOLE_TYPES", "LINK_TYPES", "GNS3TopologyTool", + "GNS3ProjectInfoTool", "get_gns3_connector", "get_gns3_connector_with_llm_config", "get_gns3_server_host", diff --git a/gns3server/agent/gns3_copilot/gns3_client/gns3_project_info.py b/gns3server/agent/gns3_copilot/gns3_client/gns3_project_info.py new file mode 100644 index 000000000..e59f7460e --- /dev/null +++ b/gns3server/agent/gns3_copilot/gns3_client/gns3_project_info.py @@ -0,0 +1,126 @@ +""" +This module provides a LangChain BaseTool to retrieve basic information of a +specific GNS3 project by project ID. +""" + +import logging +from typing import Any + +from langchain.tools import BaseTool + +from gns3server.agent.gns3_copilot.gns3_client import Project, get_gns3_connector + +# Configure logging +logger = logging.getLogger(__name__) + + +class GNS3ProjectInfoTool(BaseTool): + """LangChain tool for retrieving GNS3 project basic information.""" + + name: str = "gns3_project_info" + description: str = """ + Retrieves basic information of a GNS3 project including name, status, node count and link count. + + Input: `project_id` (str, required): UUID of the GNS3 project. + + Output: Dictionary with: + - `project_id`: Project UUID + - `name`: Project name + - `status`: Project status (opened/closed) + - `node_count`: Number of nodes in the project + - `link_count`: Number of links in the project + + Returns a tuple format: (name, project_id, node_count, link_count, status) + """ + + def _run( + self, + tool_input: Any = None, + run_manager: Any = None, + project_id: str | None = None, + ) -> dict: + """ + Synchronous method to retrieve basic information of a specific GNS3 project. + + Args: + tool_input : Input parameters, typically a dict or Pydantic model. + run_manager : Callback manager for tool run. + project_id : The UUID of the specific GNS3 project. + + Returns: + dict: A dictionary containing project info (name, project_id, node_count, link_count, status), + or an error dictionary if an exception occurs or project_id is not provided. + """ + + # Log received input + logger.info("Received tool_input: %s, project_id: %s", tool_input, project_id) + + try: + # Validate project_id parameter + if not project_id: + logger.error("project_id parameter is required.") + return { + "error": "project_id parameter is required. Please provide a valid project UUID." + } + + # Initialize Gns3Connector using factory function + logger.info("Connecting to GNS3 server...") + server = get_gns3_connector() + + if server is None: + logger.error("Failed to create GNS3 connector") + return { + "error": "Failed to connect to GNS3 server. Please check your configuration." + } + + # Use the provided project_id directly + logger.info(f"Retrieving project info for project_id: {project_id}") + project = Project(project_id=project_id, connector=server) + project.get() # Load project details + + # Get node and link counts + nodes_inventory = project.nodes_inventory() + links_summary = project.links_summary(is_print=False) + + node_count = len(nodes_inventory) if nodes_inventory else 0 + link_count = len(links_summary) if links_summary else 0 + + # Build result in tuple format consistent with GNS3ProjectList + result = { + "project_id": project.project_id, + "name": project.name, + "status": project.status, + "node_count": node_count, + "link_count": link_count, + "tuple": (project.name, project.project_id, node_count, link_count, project.status), + } + + # Log result + logger.info("Project info retrieved: name=%s, status=%s, nodes=%d, links=%d", + project.name, project.status, node_count, link_count) + + return result + + except Exception as e: + logger.error("Error retrieving GNS3 project info: %s", str(e)) + return {"error": f"Failed to retrieve project info: {str(e)}"} + + +if __name__ == "__main__": + from pprint import pprint + + # Test the tool + tool = GNS3ProjectInfoTool() + + # Example usage with project_id + # Replace with an actual project UUID from your GNS3 server + example_project_id = "0c0fde25-6ead-4413-a283-ea8fd2324291" + + print("Testing GNS3ProjectInfoTool with project_id...") + result = tool._run(project_id=example_project_id) + pprint(result) + + # Test without project_id (should return error) + print("\nTesting without project_id (should return error)...") + error_result = tool._run() + pprint(error_result)