From cd1d28729aa6b423978678c0b5dfce32140dbffd Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 18 Mar 2026 15:21:23 +0800 Subject: [PATCH] feat: make AI Copilot an optional dependency This change makes AI Copilot features optional to reduce installation size and support restricted environments. Changes: - Split AI dependencies into ai-requirements.txt - Add ai-copilot optional dependency in pyproject.toml - Add import protection in gns3server/agent/__init__.py - Return 501 for AI endpoints when dependencies not installed - Add gns3server-uninstall-ai-copilot command for cleanup - Update README with installation and uninstallation instructions Installation: - Basic: pip install gns3-server - With AI: pip install gns3-server[ai-copilot] - Development: pip install gns3-server[ai-copilot,dev] Uninstallation: - gns3server-uninstall-ai-copilot --- README.md | 53 ++++++++++- ai-requirements.txt | 49 +++++++++++ gns3server/agent/__init__.py | 75 ++++++++++++++++ gns3server/api/routes/controller/__init__.py | 30 +++++-- gns3server/schemas/__init__.py | 43 +++++---- gns3server/utils/uninstall_ai_copilot.py | 92 ++++++++++++++++++++ pyproject.toml | 6 ++ requirements.txt | 65 +++----------- 8 files changed, 337 insertions(+), 76 deletions(-) create mode 100644 ai-requirements.txt create mode 100644 gns3server/agent/__init__.py create mode 100644 gns3server/utils/uninstall_ai_copilot.py diff --git a/README.md b/README.md index 0bfb33bd4..b714503d5 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,45 @@ python3 -m pip install gns3-gui python3 -m pip install gns3-server ``` +#### Optional Features + +GNS3 server supports optional features that can be installed as needed: + +**AI Copilot** (Optional): +```shell +python3 -m pip install gns3-server[ai-copilot] +``` +AI-powered assistant for network topology design and automation. + +**Development** (For contributors): +```shell +python3 -m pip install gns3-server[dev] +``` + +**Combination Installation**: +You can install multiple optional features together: +```shell +python3 -m pip install gns3-server[ai-copilot,dev] +``` + +**Why optional?** +- Reduces installation size for users who don't need specific features +- Supports restricted environments (government, education, corporate) where certain libraries may not be allowed +- Faster installation for basic GNS3 usage +- Allows users to choose only the features they need + +**Note:** If you install without optional extras, the server will work normally but optional features will be disabled. You can add features later by running the appropriate install command. + +**Uninstalling AI Copilot:** + +To remove AI Copilot dependencies: + +```shell +gns3server-uninstall-ai-copilot +``` + +This will remove all AI Copilot dependencies while keeping the core functionality intact. The server will continue to work, but AI features will return a 501 (Not Implemented) status code. + The downside of this method is you will have to manually install all dependencies (see below). Please see our [documentation](https://docs.gns3.com/docs/getting-started/installation/linux) for more details. @@ -77,7 +116,7 @@ Note that Docker needs the script program (`bsdutils` or `util-linux` package), ### Setting up -These commands will install the server as well as all Python dependencies: +These commands will install the server with core Python dependencies: ```shell git clone https://github.com/GNS3/gns3-server @@ -89,6 +128,18 @@ python3 -m pip install . python3 -m gns3server ``` +**For AI Copilot development**, install with additional dependencies: + +```shell +python3 -m pip install .[ai-copilot,dev] +``` + +**For development (tests and linting)**: + +```shell +python3 -m pip install .[dev] +``` + You will have to manually install other software dependencies (see above), for Dynamips, VPCS and uBridge the easiest is to install from our PPA. ### Docker container diff --git a/ai-requirements.txt b/ai-requirements.txt new file mode 100644 index 000000000..9c3c1f189 --- /dev/null +++ b/ai-requirements.txt @@ -0,0 +1,49 @@ +# ============================================================================== +# GNS3 Copilot AI Agent Dependencies +# ============================================================================== +# Install with: pip install gns3-server[ai-copilot] +# Or directly: pip install -r ai-requirements.txt +# ============================================================================== + +# Core AI and Automation Framework +# Note: aiosqlite is in core requirements.txt +langchain>=1.2.10 +langchain-core>=1.2.16 +langgraph>=1.0.9 +langgraph-checkpoint>=4.0.0 +langgraph-checkpoint-sqlite>=3.0.3 +langgraph-checkpoint-postgres>=3.0.4 + +# Model Providers +langchain-openai>=1.1.10 +langchain-anthropic>=1.3.4 +langchain-google-genai>=4.2.1 +langchain-aws>=1.3.1 +langchain-ollama>=1.0.1 +langchain-deepseek>=1.0.1 +langchain-xai>=1.2.2 + +# Token Counting +tiktoken>=0.8.0 + +# LangSmith SDK +langsmith>=0.7.7 + +# Network Automation +netmiko>=4.6.0 +nornir>=3.5.0 +nornir-netmiko>=1.0.1 +nornir-utils>=0.2.0 +nornir-salt>=0.23.0 + +# Telnet Client +telnetlib3>=2.0.8 + +# Environment & Configuration +python-dotenv>=1.2.1 + +# Authentication +PyJWT>=2.10.1 +psycopg-pool>=3.1.0 + +# Note: httpx is only for testing (in dev-requirements.txt) diff --git a/gns3server/agent/__init__.py b/gns3server/agent/__init__.py new file mode 100644 index 000000000..ab9ce947a --- /dev/null +++ b/gns3server/agent/__init__.py @@ -0,0 +1,75 @@ +# +# Copyright (C) 2025 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received copy of the GNU General Public License +# along with this program. If not, see . + +""" +Agent module with optional AI Copilot support. + +This module provides the AI Copilot functionality as an optional feature. +If the AI dependencies are not installed, the module will be disabled but +will not prevent the server from starting. + +Installation: + pip install gns3-server[ai-copilot] +""" + +import logging + +# Feature flag: AI Copilot is available +AI_COPILOT_AVAILABLE = False + +# Try to import AI Copilot components +try: + from .gns3_copilot.project_agent_manager import get_project_agent_manager + from .gns3_copilot.project_agent_manager import ProjectAgentManager + AI_COPILOT_AVAILABLE = True +except ImportError as e: + # AI dependencies not installed, disable AI Copilot feature + logging.warning( + f"AI Copilot dependencies not installed: {e}. " + "AI features will be disabled. Install with: pip install gns3-server[ai-copilot]" + ) + AI_COPILOT_AVAILABLE = False + + # Provide stub functions that raise helpful errors + async def get_project_agent_manager(): + """ + Get the global ProjectAgentManager singleton instance. + + Raises: + RuntimeError: If AI Copilot dependencies are not installed + """ + raise RuntimeError( + "AI Copilot is not available. " + "Install AI dependencies with: pip install gns3-server[ai-copilot]" + ) + + class ProjectAgentManager: + """ + Stub class for ProjectAgentManager when AI dependencies are not installed. + """ + + def __init__(self): + raise RuntimeError( + "AI Copilot is not available. " + "Install AI dependencies with: pip install gns3-server[ai-copilot]" + ) + + +__all__ = [ + "AI_COPILOT_AVAILABLE", + "get_project_agent_manager", + "ProjectAgentManager", +] diff --git a/gns3server/api/routes/controller/__init__.py b/gns3server/api/routes/controller/__init__.py index 7930fdff1..d48993de6 100644 --- a/gns3server/api/routes/controller/__init__.py +++ b/gns3server/api/routes/controller/__init__.py @@ -14,16 +14,36 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, HTTPException + +# Check AI Copilot availability +from gns3server.agent import AI_COPILOT_AVAILABLE + +# Conditionally import AI-dependent routes +if AI_COPILOT_AVAILABLE: + from . import chat + from . import llm_model_configs + _chat_router = chat.router + _llm_router = llm_model_configs.router +else: + # Create stub routers that return 501 for all AI endpoints + _chat_router = APIRouter() + _llm_router = APIRouter() + + @_chat_router.api_route("/{path:path}", methods=["GET", "POST", "DELETE", "PATCH", "PUT"]) + @_llm_router.api_route("/{path:path}", methods=["GET", "POST", "DELETE", "PATCH", "PUT"]) + async def ai_not_available(path: str = ""): + raise HTTPException( + status_code=501, + detail="AI Copilot is not available. Install AI dependencies with: pip install gns3-server[ai-copilot]" + ) -from . import chat from . import controller from . import appliances from . import computes from . import drawings from . import gns3vm from . import links -from . import llm_model_configs from . import nodes from . import projects from . import snapshots @@ -149,13 +169,13 @@ router.include_router( ) router.include_router( - llm_model_configs.router, + _llm_router, prefix="/access", tags=["LLM Model Configurations"] ) router.include_router( - chat.router, + _chat_router, prefix="/projects/{project_id}/chat", tags=["Chat"] ) diff --git a/gns3server/schemas/__init__.py b/gns3server/schemas/__init__.py index 2ea48dd6c..623a3d11d 100644 --- a/gns3server/schemas/__init__.py +++ b/gns3server/schemas/__init__.py @@ -30,24 +30,31 @@ from .controller.gns3vm import GNS3VM from .controller.nodes import NodeCreate, NodeUpdate, NodeDuplicate, NodeCapture, Node from .controller.projects import ProjectCreate, ProjectUpdate, ProjectDuplicate, Project, ProjectFile, ProjectCompression from .controller.users import UserCreate, UserUpdate, LoggedInUserUpdate, User, Credentials, UserGroupCreate, UserGroupUpdate, UserGroup -from .controller.llm_model_configs import ( - LLMModelConfigData, - LLMModelConfigCreate, - LLMModelConfigUpdate, - LLMModelConfigResponse, - LLMModelConfigWithSource, - LLMModelConfigInheritedResponse, - LLMModelConfigListResponse -) -from .controller.chat import ( - OpenAIToolCall, - ChatRequest, - ChatResponse, - OpenAIMessage, - ConversationHistory, - ChatSession, - RenameSession -) + +# Conditionally import AI-related schemas +try: + from .controller.llm_model_configs import ( + LLMModelConfigData, + LLMModelConfigCreate, + LLMModelConfigUpdate, + LLMModelConfigResponse, + LLMModelConfigWithSource, + LLMModelConfigInheritedResponse, + LLMModelConfigListResponse + ) + from .controller.chat import ( + OpenAIToolCall, + ChatRequest, + ChatResponse, + OpenAIMessage, + ConversationHistory, + ChatSession, + RenameSession + ) +except ImportError: + # AI schemas are not available (should not happen as they don't depend on external libs) + pass + from .controller.rbac import RoleCreate, RoleUpdate, Role, Privilege, ACECreate, ACEUpdate, ACE from .controller.pools import Resource, ResourceCreate, ResourcePoolCreate, ResourcePoolUpdate, ResourcePool from .controller.tokens import Token diff --git a/gns3server/utils/uninstall_ai_copilot.py b/gns3server/utils/uninstall_ai_copilot.py new file mode 100644 index 000000000..c4908af83 --- /dev/null +++ b/gns3server/utils/uninstall_ai_copilot.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +""" +Uninstall AI Copilot dependencies. + +Usage: + gns3server-uninstall-ai-copilot + gns3server-uninstall-ai-copilot -y +""" + +import os +import sys +import subprocess +import argparse + + +def get_ai_packages(): + """Read packages from ai-requirements.txt.""" + # Find the requirements file + if hasattr(sys, '_MEIPASS'): + # PyInstaller bundle + base_dir = os.path.dirname(sys.executable) + else: + # __file__ = gns3server/utils/uninstall_ai_copilot.py + # Need to go up 2 levels to reach project root + base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + + requirements_file = os.path.join(base_dir, "ai-requirements.txt") + + packages = [] + with open(requirements_file, "r") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#"): + continue + # Remove version specifiers + package = line.split(">=")[0].split("==")[0].split("~=")[0] + packages.append(package) + return packages + + +def uninstall(packages, yes=False): + """Uninstall packages.""" + if not packages: + print("No packages found to uninstall.") + return + + print(f"Found {len(packages)} AI Copilot dependencies:") + for pkg in packages: + print(f" - {pkg}") + print() + + if not yes: + response = input("Do you want to uninstall these packages? [y/N]: ") + if response.lower() != "y": + print("Cancelled.") + return + + print("Uninstalling...") + for package in packages: + try: + result = subprocess.run( + [sys.executable, "-m", "pip", "uninstall", "-y", package], + capture_output=True, + text=True + ) + if result.returncode == 0: + print(f" Removed: {package}") + else: + print(f" Failed to remove {package} (may not be installed)") + except Exception as e: + print(f" Error removing {package}: {e}") + + print("\nAI Copilot dependencies have been uninstalled.") + print("You can reinstall them with: pip install gns3-server[ai-copilot]") + + +def main(): + parser = argparse.ArgumentParser( + description="Uninstall AI Copilot dependencies" + ) + parser.add_argument( + "-y", "--yes", action="store_true", + help="Automatically confirm uninstallation" + ) + args = parser.parse_args() + + packages = get_ai_packages() + uninstall(packages, yes=args.yes) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index 6142f1dcd..fe9314b91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,8 +38,13 @@ version = {attr = "gns3server.version.__version__"} dependencies = {file = "requirements.txt"} [tool.setuptools.dynamic.optional-dependencies] +# Development dependencies dev = {file = ['dev-requirements.txt']} +# Optional components (can be installed individually or combined) +ai-copilot = {file = ['ai-requirements.txt']} +# terraform = {file = ['terraform-requirements.txt']} # Future component + [project.urls] "Homepage" = "http://gns3.com" "Repository" = "http://github.com/GNS3/gns3-server" @@ -48,3 +53,4 @@ dev = {file = ['dev-requirements.txt']} [project.scripts] gns3server = "gns3server.main:main" gns3vmnet = "gns3server.utils.vmnet:main" +gns3server-uninstall-ai-copilot = "gns3server.utils.uninstall_ai_copilot:main" diff --git a/requirements.txt b/requirements.txt index 0fe700a01..4a32f8eda 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,58 +24,19 @@ zstandard==0.25.0 platformdirs>=2.4.0,<3 # platformdirs >=3 conflicts when building Debian packages truststore>=0.10.4; python_version >= '3.10' -# ============================================================================== -# GNS3 Copilot AI Agent Dependencies -# ============================================================================== - -# Core AI and Automation Framework -aiosqlite>=0.19.0 -langchain>=1.2.10 -langchain-core>=1.2.16 -langgraph>=1.0.9 -langgraph-checkpoint>=4.0.0 -langgraph-checkpoint-sqlite>=3.0.3 -langgraph-checkpoint-postgres>=3.0.4 - -# Model Providers -langchain-openai>=1.1.10 -langchain-anthropic>=1.3.4 -langchain-google-genai>=4.2.1 -langchain-aws>=1.3.1 -langchain-ollama>=1.0.1 -langchain-deepseek>=1.0.1 -langchain-xai>=1.2.2 - -# Token Counting -tiktoken>=0.8.0 - -# LangSmith SDK -langsmith>=0.7.7 - -# Network Automation -netmiko>=4.6.0 -nornir>=3.5.0 -nornir-netmiko>=1.0.1 -nornir-utils>=0.2.0 -nornir-salt>=0.23.0 - -# Telnet Client -telnetlib3>=2.0.8 - -# Environment & Configuration -python-dotenv>=1.2.1 - -# HTTP Requests +# Shared dependencies (also used by AI Copilot) +typing-extensions>=4.15.0 requests>=2.32.5 urllib3>=2.6.2 -httpx>=0.27.0 -# Authentication -PyJWT>=2.10.1 -psycopg-pool>=3.1.0 - -# Type Extensions -typing-extensions>=4.15.0 - -# Image Processing -Pillow>=12.1.1 +# ============================================================================== +# AI Copilot Optional Dependencies +# ============================================================================== +# AI Copilot features are now optional. Install with: +# pip install gns3-server[ai-copilot] +# Or: +# pip install -r ai-requirements.txt +# +# This reduces installation size and supports restricted environments where +# AI dependencies may not be allowed. +# ==============================================================================