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.
- Add info and debug logging to llm_call node for tracking LLM invocations and configuration
- Add error handling and logging to tool_node for tool execution failures
- Add startup logging to stream_chat method with session details
- Improve observability of agent workflow and debugging capabilities
The `get_gns3_connector` function now accepts an optional `jwt_token` parameter. If not provided, the token will be retrieved from context, improving flexibility for scenarios where authentication is handled externally or deferred.
The `stream_chat` method was yielding a "done" message after streaming all chunks, but this is unnecessary as the streaming completion is already indicated by the end of the stream. Removing this redundant message simplifies the response handling and aligns with typical streaming patterns.
Add project status validation to all chat API endpoints to ensure the project is opened before allowing chat operations. This prevents unauthorized access and ensures chat functionality only works with active projects.
- Check project.status == "opened" in stream_chat, list_sessions, get_history, and delete_session endpoints
- Return HTTP 403 FORBIDDEN with descriptive error message if project is not opened
- Update docstring for stream_chat endpoint to document the requirement
- Refactor `llm_call` and `generate_title` nodes to retrieve `llm_config` from request-scoped context variable instead of LangGraph config
- Remove `jwt_token` and `llm_config` from LangGraph configurable parameters in `AgentService.stream`
- Add `set_current_llm_config` and `get_current_llm_config` functions to `connector_factory` and export them in `__init__.py`
- Update `tool_node` to no longer extract `jwt_token` from config as it is now handled via context variable
- Improves thread safety and decouples configuration from LangGraph's state management
- Move JWT token from state to configurable context for better security and request isolation
- Add user_id parameter to agent service for enhanced metadata tracking
- Update checkpoint directory name from .gns3-copilot to gns3-copilot
- Implement context-aware JWT token management using ContextVar
- Improve tool node to extract JWT token from config instead of state
Update agent service to properly access content from AIMessageChunk objects during chat model streaming. Instead of using dictionary get method on the chunk, now use getattr to directly access the content attribute, ensuring compatibility with the AIMessageChunk object structure.
- Replace separate user_id and jwt_token parameters with unified llm_config dict
- Simplify model factory to accept llm_config directly instead of fetching from API
- Update llm_call and generate_title nodes to extract llm_config from LangGraph config
- Remove deprecated API fetching logic from model factory
- Maintain backward compatibility for existing tool usage patterns
This change centralizes LLM configuration management, reducing API calls and improving performance by passing configuration directly from the API layer rather than fetching it repeatedly.
Refactor get_llm_config to handle various async contexts more robustly. The function now properly checks for running event loops using asyncio.get_running_loop() and handles edge cases when called from thread pools or existing loops. This prevents RuntimeErrors and ensures reliable execution in both sync and async environments.
Remove support for environment variable fallback in LLM model configuration. The configuration now strictly follows:
1. Provided llm_config dictionary (highest priority)
2. Fetch from llm_model_configs system via connector_factory (requires user_id and jwt_token)
This change ensures consistent configuration management and eliminates the outdated environment variable approach. When no configuration is found, a clear ValueError is raised with appropriate error messages.
- Change chat router prefix from `/chat` to `/projects/{project_id}/chat`
- Add `dep_project` dependency to inject Project instance into endpoints
- Remove manual project validation in `stream_chat` and use dependency instead
- Add placeholder `list_sessions` endpoint for future session listing
- Update `get_history` endpoint to use project dependency and adjust path
- Improve code organization and error handling for project retrieval
Add explicit Query parameter with description to the `list_sessions` endpoint for better API documentation and clarity. The `project_id` parameter now includes a descriptive label indicating it is a GNS3 project ID.
- Change config parameter type from dict to RunnableConfig | None in llm_call and generate_title functions
- This improves type safety and aligns with LangChain's RunnableConfig usage
- No functional changes, only type annotations updated for better integration
Updated import statements across multiple agent files to use absolute paths starting with `gns3server.agent.gns3_copilot` instead of relative `gns3_copilot` imports. This ensures proper module resolution within the gns3-server package structure and prevents import errors when the agent is executed from different contexts.
- Modified `llm_call` and `generate_title` functions to accept `config` parameter, extracting `user_id` and `jwt_token` for per-user LLM configuration and API authentication
- Updated `create_base_model_with_tools` and `create_title_model` calls to pass user authentication details
- Added `jwt_token` to state for tool usage in GNS3 API calls
- Integrated chat router into controller API routes under `/chat` endpoint
- Implemented `_cleanup_copilot_agent` method in `Project` class to remove AgentService resources upon project closure, preventing resource leaks
- Enhanced error handling in agent cleanup to avoid interrupting project close operations
This commit introduces a comprehensive design document outlining the implementation of AI Chat API for GNS3 Copilot Agent within GNS3 Server. The document provides:
- Overview and background on existing components including GNS3 Copilot Agent, LLM configuration management, and API framework
- Reference implementation details from FlowNet-Lab project
- Architecture design with clear component interactions between frontend clients and backend services
- RESTful API specifications for chat streaming, session management, and history retrieval
- Implementation details covering project-based agent management, SQLite checkpoint storage, and LangGraph integration
- Security considerations and deployment guidelines
The design enables clients to interact with GNS3 Copilot Agent through standardized APIs, supporting real-time chat streaming and persistent conversation sessions per project.
Removed GNS3UpdateDrawingTool import and from __all__ list in gns3_client __init__.py to clean up the public interface and eliminate unused or deprecated components.
Update all references from FlowNet-Lab to GNS3-Copilot in package names, documentation, and logging. This includes:
- Module and package __init__.py files
- License headers and file descriptions
- Log messages and internal comments
- Remove deprecated tools: GNS3CreateAreaDrawingTool and LinuxTelnetBatchTool
The renaming aligns with the project's new branding while maintaining all existing functionality.
Add comprehensive dependencies for the new GNS3 Copilot AI agent feature. This includes:
- Core AI and automation frameworks (LangChain, LangGraph)
- Multiple model provider integrations (OpenAI, Anthropic, Google, AWS, Ollama, DeepSeek, xAI)
- Network automation tools (Netmiko, Nornir)
- Supporting libraries for telnet, HTTP requests, authentication, and image processing
The dependencies are organized into a dedicated section with clear comments for maintainability.
Refactor model factory to support three configuration sources in priority order:
1. Direct llm_config dictionary parameter
2. Fetch from llm_model_configs system via connector_factory (requires user_id and jwt_token)
3. Environment variables as fallback for backward compatibility
This improves flexibility by allowing runtime configuration while maintaining compatibility with existing environment-based setups.
Removed checkpoint-related imports and exports from the agent package's __init__.py to clean up the public API. This change reduces unnecessary exposure of internal checkpoint utility functions, focusing the public interface on the core agent_builder functionality.
- Add `get_gns3_server_host()` function to `connector_factory.py` for extracting GNS3 server hostname from controller, config, or default URL
- Export new function in `__init__.py` for public API access
- Replace `os.getenv("GNS3_SERVER_HOST", "127.0.0.1")` calls with `get_gns3_server_host()` in Nornir configuration tools (`config_tools_nornir.py`, `display_tools_nornir.py`)
- Ensures consistent host detection across tools using the same priority logic as `get_gns3_connector`
Removed GNS3_SERVER_USERNAME and GNS3_SERVER_PASSWORD environment variables from Nornir configuration tools. Credentials are now set to empty strings by default, simplifying configuration and removing dependency on environment variables for authentication.
- Rename module description from FlowNet-Lab to GNS3 Copilot
- Replace linux_specialist_prompt and experiment_deploy_prompt imports with base_prompt
- Update __all__ export list to include SYSTEM_PROMPT instead of removed prompts
- Improve module docstring with detailed component descriptions and available prompts
- Maintain dynamic version management and module metadata
- Remove direct logging of LLM config from gns3_copilot.py
- Update model_factory to accept configuration from llm_model_configs dictionary
- Add fallback to environment variables for backward compatibility
- Centralize configuration loading in _load_llm_config function
Introduce `get_gns3_connector_with_llm_config` as a convenience function that combines the creation of a GNS3 API connector and retrieval of the user's default LLM configuration. This simplifies initialization for operations requiring both GNS3 connectivity and AI model settings, reducing boilerplate code in callers. The function returns a dictionary containing the connector and LLM config, or None on failure.
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
Updated documentation and implementation to clearly define the priority order for selecting default LLM model configurations. The logic now explicitly states:
1. User's config marked with `is_default: true` (highest priority)
2. Group's config marked with `is_default: true`
3. First config in the list (user configs come before group configs)
This ensures consistent behavior between the API documentation and the actual implementation in the repository code.
Update API documentation to reflect new nested `config` object structure in LLM model configurations endpoints. The response format now encapsulates provider-specific fields (provider, base_url, model, temperature, api_key, max_tokens) within a `config` object, while moving ownership metadata (user_id, group_id, is_default, version, created_at, updated_at) to the top level. This aligns the user-facing endpoints with the group configuration structure and improves API consistency.
- Add note clarifying that GET endpoints for groups return the same structure as user endpoints
- Document LLMModelConfigListResponse schema with default configuration selection logic
- Add comprehensive example for GET group configurations endpoint
- Update endpoint numbering to accommodate new group endpoints
- Ensure consistency between user and group API documentation
- Update API documentation to explicitly describe default configuration selection logic
- Add fallback behavior in repository to use first config when no default is marked
- Clarify difference between `/default` endpoint and `default_config` field
- Document that `default_config` is never null when configs list is not empty
- Add `/default` endpoints for users and groups to retrieve default LLM model configurations
- Update documentation to clarify that users receive both own and inherited configurations
- Improve response examples to show combined configs with source field
- Add 404 response example for missing default configurations
- Fix optimistic locking documentation formatting
Add explicit datetime.utcnow() assignments for created_at and updated_at fields in LLMModelConfigsRepository to ensure proper timestamp handling with SQLite. This addresses issues where SQLite may not automatically populate these timestamp fields during create and update operations. Changes applied to both user and group configuration methods for consistency.
When no configuration file is found or readable, the server now still loads secret files. This ensures that secret configurations (like API keys or passwords) are available even if the primary config file is missing, improving robustness and security in environments where secrets are stored separately.
- Change `JSONB` columns to generic `JSON` in LLMModelConfig model for database compatibility
- Update migration to use `sa.String(32)` for UUID and `sa.JSON()` for config fields
- Remove PostgreSQL dialect imports to support multiple database backends
- Keep existing constraints and indexes with PostgreSQL-specific annotations where needed
The migration file `20260303_create_llm_model_configs_table.py` had an incorrect `down_revision` reference. Changed from `7ceeddd9c9a8` to `98083573d011` to properly link to the previous migration in the Alembic history. This ensures the migration chain is consistent and rollbacks work as expected.
Replace deferred UniqueConstraints with partial unique indexes for user and group default configurations in the LLM model configs table. This change improves performance and ensures at most one default config per user/group while maintaining data integrity. The migration script has been updated accordingly to create and drop the new indexes.
- Add `model_type` field to database schema with supported values (text, vision, stt, tts, multimodal, embedding, reranking, other)
- Add `name` field as table-level column for indexing and filtering
- Add reserved JSONB fields for future extensibility
- Update API request/response schemas to include `model_type` and `name` fields
- Add new `LLMModelConfigWithSource` schema for detailed configuration responses
- Update usage examples to reflect new required fields
- Improve database constraints and indexing documentation
Add comprehensive documentation for optimistic locking implementation in the LLM model configurations API. The update includes:
- Added "Optimistic Locking" feature to the overview section
- Added `version` field to the database schema table
- Updated `LLMModelConfigUpdate` schema to include `expected_version` parameter
- Updated `LLMModelConfigResponse` schema to include `version` field
- Added detailed examples for update operations with optimistic locking
- Included conflict handling workflow and client retry instructions
This documentation ensures users understand how to prevent concurrent modification conflicts when updating LLM model configurations.
- Include `version` field in all LLM model config response schemas
- Add `expected_version` parameter to update endpoints for optimistic locking
- Handle concurrent modification errors with HTTP 409 Conflict status
- Update both user and group config endpoints consistently
Add a new method `_load_encryption_key` to initialize encryption for sensitive data such as API keys. This method is called within `_load_secret_files` alongside JWT secret key loading, ensuring encryption is set up during server configuration. The change enhances security by enabling encryption for secrets stored in the server's secrets directory.
- Add smarter database state detection during initialization to handle new databases, existing databases with new features, and old databases needing migration
- Make migration for llm_model_configs table idempotent to prevent conflicts when table already exists from code
- Add detailed logging for different database initialization scenarios
- Import sqlalchemy module for database inspection capabilities
- Introduce new API route `/access` for managing LLM model configurations
- Add LLMModelConfig model to database models
- Include comprehensive schemas for LLM model config CRUD operations
- Register new router with tags for LLM Model Configurations
When a Docker container with the same name already exists (e.g., from a
previous crashed GNS3 session), Docker returns a 409 Conflict error
when trying to create a new container with that name. This causes the
project open operation to fail.
This fix adds automatic cleanup of stale containers when encountering
a name conflict:
- Added DockerHttp409Error exception class
- Updated http_query to detect 409 status codes
- Modified create() to remove conflicting containers and retry
Fixes the issue where opening a project fails with:
"Docker has returned an error: 409 Conflict. The container name
'/GNS3.xxx' is already in use by container 'xxx'"