"""
GNS3 drawings retrieval tool for managing graphical elements.
Provides functionality to retrieve all drawings from a GNS3 project,
including their coordinates, SVG content, and other properties.
"""
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 GNS3GetDrawingsTool(BaseTool):
"""
A LangChain tool to retrieve all drawings from a GNS3 project.
**Input:**
A JSON object containing the project_id.
Example input:
{
"project_id": "uuid-of-project"
}
**Output:**
A dictionary containing all drawings in the project.
Example output:
{
"project_id": "uuid-of-project",
"drawings": [
{
"drawing_id": "uuid-of-drawing1",
"svg": "",
"x": 100,
"y": 200,
"z": 0,
"locked": false,
"rotation": 0
},
{
"drawing_id": "uuid-of-drawing2",
"svg": "",
"x": 300,
"y": 400,
"z": 1,
"locked": true,
"rotation": 90
}
],
"total_drawings": 2
}
If an error occurs during input validation, returns a dictionary with an error message.
"""
name: str = "get_gns3_drawings"
description: str = """
Retrieves all drawings from a GNS3 project.
Input is a JSON object with project_id.
Example input:
{
"project_id": "uuid-of-project"
}
Returns a dictionary with all drawings in the project, including their drawing_id,
svg content, coordinates (x, y), z-index, locked status, and rotation.
If the operation fails, returns a dictionary with an error message.
"""
def _run(
self,
tool_input: str,
run_manager: CallbackManagerForToolRun | None = None,
**kwargs: Any,
) -> dict[str, Any]:
"""
Retrieves all drawings from a GNS3 project.
Args:
tool_input (str): A JSON string containing project_id.
run_manager: LangChain run manager (unused).
Returns:
dict: A dictionary with all drawings in the project 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")
# Validate input
if not project_id:
logger.error("Invalid input: Missing project_id.")
return {"error": "Missing 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."
}
# Create project instance
logger.info("Retrieving drawings from project %s...", project_id)
project = Project(project_id=project_id, connector=gns3_server)
# Get project drawings
project.get_drawings()
# Prepare drawing list
drawings_list = []
if project.drawings:
for drawing in project.drawings:
drawing_info = {
"drawing_id": drawing.get("drawing_id"),
"svg": drawing.get("svg"),
"x": drawing.get("x"),
"y": drawing.get("y"),
"z": drawing.get("z"),
"locked": drawing.get("locked"),
"rotation": drawing.get("rotation", 0),
}
drawings_list.append(drawing_info)
# Prepare final result
final_result = {
"project_id": project_id,
"drawings": drawings_list,
"total_drawings": len(drawings_list),
}
# Log the final result
logger.info(
"Retrieved %d drawings from project %s.",
len(drawings_list),
project_id,
)
# 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 retrieve drawings: %s", e)
return {"error": f"Failed to retrieve drawings: {str(e)}"}
if __name__ == "__main__":
# Test the tool locally
test_input = json.dumps(
{
"project_id": "d7fc094c-685e-4db1-ac11-5e33a1b2e066"
} # Replace with actual project UUID
)
tool = GNS3GetDrawingsTool()
result = tool._run(test_input)
pprint(result)
"""
example output:
{'drawings': [{'drawing_id': 'e8202c5e-bd0a-447c-848c-15db2c9af2f0',
'locked': False,
'rotation': 0,
'svg': '',
'x': -376,
'y': -381,
'z': 1},
{'drawing_id': '7d2f2411-efe8-4f3a-9882-cc0ad7798ee0',
'locked': False,
'rotation': 0,
'svg': '',
'x': -394,
'y': 4,
'z': 1},
{'drawing_id': '264be3ab-002c-4b1d-886d-b4c323de845a',
'locked': False,
'rotation': 0,
'svg': '',
'x': -596,
'y': -43,
'z': 1},
{'drawing_id': '44210a41-0100-46a0-8962-a73c72171c47',
'locked': False,
'rotation': 0,
'svg': '',
'x': -573,
'y': -272,
'z': 1},
{'drawing_id': 'efd1add9-a798-489d-af26-58b2d73c89dc',
'locked': False,
'rotation': 0,
'svg': '',
'x': -636,
'y': -152,
'z': 1},
{'drawing_id': '89913ef3-1041-4b11-94e1-c5d65c3a52d4',
'locked': False,
'rotation': 0,
'svg': '',
'x': -891,
'y': 66,
'z': 1}],
'project_id': '2245149a-71c8-4387-9d1f-441a683ef7e7',
'total_drawings': 8}
"""