- 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'"
Add an additional fallback check for the VBoxManage executable using the capitalized "VBoxManage" command name. This improves compatibility on systems where the executable may be case-sensitive or installed with a different naming convention, ensuring the VirtualBox manager can locate the necessary binary when the lowercase "vboxmanage" is not found.
Refactor port name assignment to use `or` operator for fallback values, improving code readability and consistency. Changes applied in `node.py` and `port_factory.py` to handle custom adapter settings more cleanly.
Add conditional checks to ensure `self._name` is not None before performing string operations in the `short_name` property. This prevents potential AttributeError exceptions when port name is undefined, improving robustness and compatibility with edge cases in port configuration.
Use dict.get() method to safely access 'image' and 'path' keys in settings dictionary to avoid KeyError exceptions when these keys are missing. This improves error handling and prevents server crashes when creating templates with incomplete settings.
- Use `default=str` in `json.dumps` to handle non-serializable objects
- Return proper HTTP 304 response with ETag header instead of raising exception
- Ensure consistent ETag generation for template caching