mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-09-12 13:05:32 +03:00
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
293 lines
10 KiB
Python
293 lines
10 KiB
Python
"""
|
|
GNS3 drawing creation tool for adding graphical elements.
|
|
|
|
Provides functionality to create multiple drawings in a GNS3 project
|
|
using specified SVG content and coordinates through the GNS3 API.
|
|
"""
|
|
|
|
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 Project, get_gns3_connector
|
|
|
|
# Configure logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class GNS3CreateDrawingTool(BaseTool):
|
|
"""
|
|
A LangChain tool to create multiple drawings in a GNS3 project
|
|
using specified SVG content and coordinates.
|
|
|
|
**Input:**
|
|
A JSON object containing the project_id and an array of drawings with SVG content,
|
|
coordinates, and optional properties.
|
|
|
|
Example input:
|
|
{
|
|
"project_id": "uuid-of-project",
|
|
"drawings": [
|
|
{
|
|
"svg": "<svg>...</svg>",
|
|
"x": 100,
|
|
"y": -200,
|
|
"z": 0,
|
|
"locked": false,
|
|
"rotation": 0
|
|
},
|
|
{
|
|
"svg": "<svg>...</svg>",
|
|
"x": -200,
|
|
"y": 300,
|
|
"z": 1,
|
|
"locked": true,
|
|
"rotation": 90
|
|
}
|
|
]
|
|
}
|
|
|
|
**Output:**
|
|
A dictionary containing the creation results for all drawings.
|
|
Example output:
|
|
{
|
|
"project_id": "uuid-of-project",
|
|
"created_drawings": [
|
|
{
|
|
"drawing_id": "uuid-of-drawing1",
|
|
"status": "success"
|
|
},
|
|
{
|
|
"drawing_id": "uuid-of-drawing2",
|
|
"status": "success"
|
|
}
|
|
],
|
|
"total_drawings": 2,
|
|
"successful_drawings": 2,
|
|
"failed_drawings": 0
|
|
}
|
|
If an error occurs during input validation, returns a dictionary with an error message.
|
|
"""
|
|
|
|
name: str = "create_gns3_drawing"
|
|
description: str = """
|
|
Creates multiple drawings in a GNS3 project using specified SVG content and coordinates.
|
|
Input is a JSON object with project_id and an array of drawings, each containing svg, x, y,
|
|
and optional z, locked, and rotation parameters.
|
|
Example input:
|
|
{
|
|
"project_id": "uuid-of-project",
|
|
"drawings": [
|
|
{
|
|
"svg": "<svg>...</svg>",
|
|
"x": 100,
|
|
"y": -200,
|
|
"z": 0,
|
|
"locked": false,
|
|
"rotation": 0
|
|
}
|
|
]
|
|
}
|
|
Returns a dictionary with creation results for all drawings, including success/failure status.
|
|
If the operation fails during input validation, returns a dictionary with an error message.
|
|
"""
|
|
|
|
def _run(
|
|
self,
|
|
tool_input: str,
|
|
run_manager: CallbackManagerForToolRun | None = None,
|
|
**kwargs: Any,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Creates multiple drawings in a GNS3 project using the provided SVG content and coordinates.
|
|
|
|
Args:
|
|
tool_input (str): A JSON string containing project_id and an array of drawings.
|
|
run_manager: LangChain run manager (unused).
|
|
|
|
Returns:
|
|
dict: A dictionary with creation results for all drawings or an error message.
|
|
"""
|
|
# Log received input
|
|
logger.info("Received input: %s", tool_input)
|
|
|
|
try:
|
|
# Parse input JSON
|
|
input_data = json.loads(tool_input)
|
|
project_id = input_data.get("project_id")
|
|
drawings = input_data.get("drawings", [])
|
|
|
|
# Validate input
|
|
if not project_id:
|
|
logger.error("Invalid input: Missing project_id.")
|
|
return {"error": "Missing project_id."}
|
|
|
|
if not isinstance(drawings, list) or len(drawings) == 0:
|
|
logger.error("Invalid input: drawings must be a non-empty array.")
|
|
return {"error": "drawings must be a non-empty array."}
|
|
|
|
# Validate each drawing in the array
|
|
for i, drawing_data in enumerate(drawings):
|
|
if not isinstance(drawing_data, dict):
|
|
logger.error(
|
|
"Invalid input: Drawing %d must be a dictionary.", i + 1
|
|
)
|
|
return {"error": f"Drawing {i + 1} must be a dictionary."}
|
|
|
|
svg = drawing_data.get("svg")
|
|
x = drawing_data.get("x")
|
|
y = drawing_data.get("y")
|
|
|
|
if not all(
|
|
[svg, isinstance(x, (int, float)), isinstance(y, (int, float))]
|
|
):
|
|
logger.error(
|
|
"Invalid input: Drawing %d missing or invalid svg, x, or y.",
|
|
i + 1,
|
|
)
|
|
return {
|
|
"error": f"Drawing {i + 1} missing or invalid svg, x, or y."
|
|
}
|
|
|
|
# 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."
|
|
}
|
|
|
|
# Create project instance
|
|
logger.info(
|
|
"Creating %d drawings in project %s...", len(drawings), project_id
|
|
)
|
|
project = Project(project_id=project_id, connector=gns3_server)
|
|
|
|
# Create drawings
|
|
results: list[dict[str, Any]] = []
|
|
|
|
for i, drawing_data in enumerate(drawings):
|
|
try:
|
|
svg = drawing_data.get("svg")
|
|
x = drawing_data.get("x")
|
|
y = drawing_data.get("y")
|
|
z = drawing_data.get("z", 0)
|
|
locked = drawing_data.get("locked", False)
|
|
rotation = drawing_data.get("rotation", 0)
|
|
|
|
logger.info(
|
|
"Creating drawing %d/%d at coordinates (%s, %s)...",
|
|
i + 1,
|
|
len(drawings),
|
|
x,
|
|
y,
|
|
)
|
|
|
|
# Create drawing using Project method
|
|
result = project.create_drawing(
|
|
svg=svg,
|
|
x=int(x),
|
|
y=int(y),
|
|
z=int(z),
|
|
locked=bool(locked),
|
|
rotation=int(rotation),
|
|
)
|
|
|
|
drawing_info = {
|
|
"drawing_id": result.get("drawing_id"),
|
|
"status": "success",
|
|
}
|
|
|
|
results.append(drawing_info)
|
|
|
|
except Exception as e:
|
|
error_info = {
|
|
"error": f"Drawing {i + 1} creation failed: {str(e)}",
|
|
"status": "failed",
|
|
}
|
|
results.append(error_info)
|
|
logger.error("Failed to create drawing %d: %s", i + 1, e)
|
|
# Continue with next drawing even if one fails
|
|
|
|
# Calculate summary statistics
|
|
successful_drawings = len(
|
|
[r for r in results if r.get("status") == "success"]
|
|
)
|
|
failed_drawings = len([r for r in results if r.get("status") == "failed"])
|
|
|
|
# Prepare final result
|
|
final_result = {
|
|
"project_id": project_id,
|
|
"created_drawings": results,
|
|
"total_drawings": len(drawings),
|
|
"successful_drawings": successful_drawings,
|
|
"failed_drawings": failed_drawings,
|
|
}
|
|
|
|
# Log the final result
|
|
logger.info(
|
|
"Drawing creation completed: %d successful, %d failed out of %d total drawings.",
|
|
successful_drawings,
|
|
failed_drawings,
|
|
len(drawings),
|
|
)
|
|
|
|
# Return JSON-formatted result
|
|
return final_result
|
|
|
|
except json.JSONDecodeError as e:
|
|
logger.error("Invalid JSON input: %s", e)
|
|
return {"error": f"Invalid JSON input: {e}"}
|
|
except Exception as e:
|
|
logger.error("Failed to process drawing creation request: %s", e)
|
|
return {"error": f"Failed to process drawing creation request: {str(e)}"}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Test the tool locally with multiple drawings
|
|
test_input = json.dumps(
|
|
{
|
|
"project_id": "0c0fde25-6ead-4413-a283-ea8fd2324291", # Replace with actual project UUID
|
|
"drawings": [
|
|
{
|
|
"svg": '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="50"><text x="10" y="30" font-size="14">Label 1</text></svg>',
|
|
"x": 100,
|
|
"y": -200,
|
|
"z": 0,
|
|
"locked": False,
|
|
"rotation": 0,
|
|
},
|
|
{
|
|
"svg": '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="50"><text x="10" y="30" font-size="14">Label 2</text></svg>',
|
|
"x": 200,
|
|
"y": -300,
|
|
"z": 1,
|
|
"locked": True,
|
|
"rotation": 90,
|
|
},
|
|
],
|
|
}
|
|
)
|
|
tool = GNS3CreateDrawingTool()
|
|
result = tool._run(test_input)
|
|
pprint(result)
|
|
|
|
|
|
"""
|
|
example output:
|
|
{'created_drawings': [{'drawing_id': '52045be2-d6d9-46f8-85af-c33bf7074b6a',
|
|
'status': 'success'},
|
|
{'drawing_id': '8f1838a7-1aa4-4613-acaa-b300b23e60d5',
|
|
'status': 'success'}],
|
|
'failed_drawings': 0,
|
|
'project_id': '2245149a-71c8-4387-9d1f-441a683ef7e7',
|
|
'successful_drawings': 2,
|
|
'total_drawings': 2}
|
|
"""
|