YueGuobin 46b262a02c feat(agent): add gns3-copilot AI assistant integration module
Integrate the gns3-copilot AI assistant module to provide intelligent
   automation and interaction capabilities for GNS3 network emulation.

   Key components:
   - AI agent framework with LLM integration (supports Qwen vision model)
   - GNS3 client library for project topology management
   - Extensive prompt templates for various network operation scenarios
   - Tool library for node creation, linking, configuration, and management
   - Support for English level assessment (A1-C2) and specialized personas
   - Network drawing and topology visualization tools
   - Linux device automation via Nornir/Telnetlib
   - Window controller for UI interaction

   Features:
   - Multi-modal AI agent with vision capabilities
   - Automated network topology deployment and configuration
   - Interactive node and drawing management
   - File-based project operations (read, write, list)
   - Specialized prompts for different scenarios and skill levels
   - Comprehensive tool set for network device management
2026-03-03 23:08:07 +08:00

183 lines
6.6 KiB
Python

"""
GNS3 node retrieval tool for device information.
Provides functionality to retrieve all node instances from a project,
including node dimensions, symbol, and other attributes.
"""
import json
import logging
from pprint import pprint
from typing import Any
from langchain.tools import BaseTool
from langchain_core.callbacks import CallbackManagerForToolRun
from gns3_copilot.gns3_client import get_gns3_connector
# Configure logging
logger = logging.getLogger(__name__)
class GNS3GetNodesTool(BaseTool):
"""
A LangChain tool to retrieve all node instances from a GNS3 project.
The tool connects to the GNS3 server and extracts comprehensive node information
including dimensions, symbol, coordinates, and other attributes.
**Input:**
A JSON string with project_id parameter.
Example: '{"project_id": "uuid-of-project"}'
**Output:**
A dictionary containing a list of dictionaries, each with comprehensive node information.
Example output:
{
"nodes": [
{
"name": "R-1",
"node_id": "uuid1",
"node_type": "iou",
"height": 50,
"width": 50,
"symbol": ":/symbols/router.svg",
"x": -180,
"y": -30,
"z": 1,
"status": "started",
"ports": [
{"name": "Ethernet0/0", "short_name": "e0/0", "adapter_number": 0, "port_number": 0},
{"name": "Ethernet0/1", "short_name": "e0/1", "adapter_number": 0, "port_number": 1}
]
}
]
}
If an error occurs, returns a dictionary with an error message.
"""
name: str = "get_gns3_nodes"
description: str = """
Retrieves all node instances from a GNS3 project.
Requires a JSON string input with 'project_id' parameter.
Returns comprehensive node information including name, node_id, node_type,
height, width, symbol, coordinates (x, y, z), status, and simplified port information.
Example input: '{"project_id": "uuid-of-project"}'
Example output:
{
"nodes": [
{
"name": "R-1",
"node_id": "uuid1",
"node_type": "iou",
"height": 50,
"width": 50,
"symbol": ":/symbols/router.svg",
"x": -180,
"y": -30,
"z": 1,
"status": "started",
"ports": [
{"name": "Ethernet0/0", "short_name": "e0/0", "adapter_number": 0, "port_number": 0}
]
}
]
}
"""
def _run(
self,
tool_input: str,
run_manager: CallbackManagerForToolRun | None = None,
) -> dict[str, Any]:
"""
Connects to the GNS3 server and retrieves all nodes from the specified project.
Args:
tool_input (str): JSON string containing project_id parameter.
run_manager: LangChain run manager (unused).
Returns:
dict: A dictionary containing the list of nodes or an error message.
"""
try:
# Parse input JSON
input_data = json.loads(tool_input)
project_id = input_data.get("project_id")
if not project_id:
logger.error("Missing project_id in input")
return {"error": "Missing required parameter: project_id"}
# Initialize Gns3Connector using factory function
logger.info("Connecting to GNS3 server...")
gns3_server = get_gns3_connector()
if gns3_server is None:
logger.error("Failed to create GNS3 connector")
return {
"error": "Failed to connect to GNS3 server. Please check your configuration."
}
# Retrieve all nodes from the project
logger.info(f"Retrieving nodes from project: {project_id}")
nodes = gns3_server.get_nodes(project_id)
# Simplify and organize node information
node_info = []
for node in nodes:
# Simplify ports - keep essential information only
simplified_ports = []
if node.get("ports"):
for port in node["ports"]:
simplified_ports.append(
{
"name": port.get("name", "N/A"),
"short_name": port.get("short_name", "N/A"),
"adapter_number": port.get("adapter_number", 0),
"port_number": port.get("port_number", 0),
}
)
# Extract node information
node_data = {
"name": node.get("name", "N/A"),
"node_id": node.get("node_id", "N/A"),
"node_type": node.get("node_type", "N/A"),
"height": node.get("height"), # Node height (read-only)
"width": node.get("width"), # Node width (read-only)
"symbol": node.get("symbol", "N/A"),
"x": node.get("x"),
"y": node.get("y"),
"z": node.get("z"),
"status": node.get("status", "N/A"),
"console": node.get("console"),
"console_type": node.get("console_type", "N/A"),
"ports": simplified_ports,
}
node_info.append(node_data)
# Return JSON-formatted result
result = {"nodes": node_info}
logger.info(
"Node retrieval completed. Total nodes: %d.",
len(node_info),
)
return result
except json.JSONDecodeError as e:
logger.error("Failed to parse input JSON: %s", e)
return {"error": f"Invalid JSON input: {str(e)}"}
except Exception as e:
logger.error("Failed to connect to GNS3 server or retrieve nodes: %s", e)
return {"error": f"Failed to retrieve nodes: {str(e)}"}
if __name__ == "__main__":
# Test the tool locally
tool = GNS3GetNodesTool()
# Example: Replace with your actual project_id
test_project_id = "d7fc094c-685e-4db1-ac11-5e33a1b2e066"
result = tool._run(f'{{"project_id": "{test_project_id}"}}')
pprint(result)