From 13a032ea2c2b5dc303f3e8570134eaa53d0e1fc8 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Mon, 9 Mar 2026 11:46:28 +0800 Subject: [PATCH] chore: update author name and copyright headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated the author name and copyright statements across the gns3_copilot module. The name has been standardized from "Guobin Yue" to "Yue Guobin (岳国宾)" to reflect the correct author attribution including Chinese characters. --- docs/gns3-copilot/DESIGN_DOCS_LICENSE.md | 50 + docs/gns3-copilot/ai-chat-api-design.md | 29 + docs/gns3-copilot/command-security.md | 29 + .../gns3-copilot/context-window-management.md | 29 + docs/gns3-copilot/llm-model-configs-api.md | 29 + .../todo/acl-web-ui-implementation-guide.md | 29 + .../todo/enhance-user-me-endpoint.md | 29 + .../todo/hitl-implementation-plan.md | 29 + .../todo/multi-user-concurrency-control.md | 29 + .../todo/orphan-tool-calls-recovery.md | 29 + .../gns3-copilot/todo/runtime-agent-params.md | 29 + .../todo/runtime-llm-config-override.md | 781 +++++++++++++ ...sse-interruption-and-agent-cancellation.md | 29 + .../todo/tool-response-format-standard.md | 29 + .../user-selectable-group-default-config.md | 29 + .../todo/vision-topology-creation.md | 1009 +++++++++++++++++ .../datetime-timezone-issue.md | 29 + .../force-kill-residual-processes.md | 29 + gns3server/agent/gns3_copilot/__init__.py | 6 +- .../agent/gns3_copilot/agent/__init__.py | 6 +- .../gns3_copilot/agent/context_manager.py | 4 +- .../agent/gns3_copilot/agent/gns3_copilot.py | 4 +- .../agent/gns3_copilot/agent/model_factory.py | 4 +- .../agent/gns3_copilot/agent_service.py | 4 +- .../gns3_copilot/chat_sessions_repository.py | 4 +- .../config/forbidden_commands.txt | 4 +- .../gns3_copilot/gns3_client/__init__.py | 6 +- .../gns3_client/connector_factory.py | 4 +- .../gns3_client/context_helpers.py | 4 +- .../gns3_copilot/gns3_client/custom_gns3fy.py | 4 +- .../gns3_client/gns3_project_info.py | 4 +- .../gns3_client/gns3_topology_reader.py | 4 +- .../gns3_copilot/project_agent_manager.py | 4 +- .../agent/gns3_copilot/prompts/__init__.py | 6 +- .../lab_automation_assistant_prompt.py | 4 +- .../gns3_copilot/prompts/prompt_loader.py | 4 +- .../prompts/teaching_assistant_prompt.py | 4 +- .../gns3_copilot/prompts/title_prompt.py | 4 +- .../agent/gns3_copilot/tools_v2/__init__.py | 8 +- .../tools_v2/config_tools_nornir.py | 4 +- .../tools_v2/display_tools_nornir.py | 4 +- .../gns3_copilot/tools_v2/gns3_create_link.py | 4 +- .../gns3_copilot/tools_v2/gns3_create_node.py | 4 +- .../tools_v2/gns3_get_node_temp.py | 4 +- .../gns3_copilot/tools_v2/gns3_start_node.py | 4 +- .../tools_v2/gns3_update_node_name.py | 4 +- .../tools_v2/vpcs_tools_telnetlib3.py | 4 +- .../agent/gns3_copilot/utils/__init__.py | 8 +- .../gns3_copilot/utils/command_filter.py | 4 +- .../utils/get_gns3_device_port.py | 4 +- .../gns3_copilot/utils/gns3_drawing_utils.py | 4 +- .../gns3_copilot/utils/llm_config_helper.py | 4 +- .../gns3_copilot/utils/message_converters.py | 4 +- .../gns3_copilot/utils/parse_tool_content.py | 6 +- .../gns3_copilot/utils/tool_call_stream.py | 4 +- 55 files changed, 2358 insertions(+), 83 deletions(-) create mode 100644 docs/gns3-copilot/DESIGN_DOCS_LICENSE.md create mode 100644 docs/gns3-copilot/todo/runtime-llm-config-override.md create mode 100644 docs/gns3-copilot/todo/vision-topology-creation.md diff --git a/docs/gns3-copilot/DESIGN_DOCS_LICENSE.md b/docs/gns3-copilot/DESIGN_DOCS_LICENSE.md new file mode 100644 index 000000000..13038d265 --- /dev/null +++ b/docs/gns3-copilot/DESIGN_DOCS_LICENSE.md @@ -0,0 +1,50 @@ +# GNS3 Copilot Design Documents License + +**Copyright © 2025 Yue Guobin (岳国宾)** ([GitHub](https://github.com/yueguobin)) + +All design documents in this directory and its subdirectories are licensed under the +Creative Commons Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0). + +## License Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: https://creativecommons.org/licenses/by-sa/4.0/ + +## What This Means + +This is a **strong copyleft** license, similar to the GPL license used for +the GNS3 server code. It ensures that: + +- Anyone can use and modify these documents +- Commercial use is permitted (training, books, etc.) +- All derivative works must remain under CC BY-SA 4.0 +- The original author must be credited + +## Icons + +License icons are available from: +- https://creativecommons.org/downloads/ +- https://chooser-beta.creativecommons.org/ + +## Contributing + +By contributing to these design documents, you agree that your contributions +will be licensed under the same CC BY-SA 4.0 license, with copyright attributed +to you respectively for your contributions. + +## Contact + +For questions about licensing, please contact: + +- GitHub: https://github.com/yueguobin diff --git a/docs/gns3-copilot/ai-chat-api-design.md b/docs/gns3-copilot/ai-chat-api-design.md index bad946f9c..b358fd732 100644 --- a/docs/gns3-copilot/ai-chat-api-design.md +++ b/docs/gns3-copilot/ai-chat-api-design.md @@ -967,3 +967,32 @@ if request.max_tokens is not None: - [LangGraph Checkpoint Documentation](https://langchain-ai.github.io/langgraph/how-tos/checkpointers/) - [Server-Sent Events (MDN)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) - [OpenAI Chat Format](https://platform.openai.com/docs/api-reference/chat) + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/command-security.md b/docs/gns3-copilot/command-security.md index 6744457f8..37f14eab8 100644 --- a/docs/gns3-copilot/command-security.md +++ b/docs/gns3-copilot/command-security.md @@ -431,3 +431,32 @@ If you: - Have suggestions for improving the filtering system Please submit an issue: https://github.com/yueguobin/gns3-copilot/issues + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/context-window-management.md b/docs/gns3-copilot/context-window-management.md index 2515fe72a..95e4bca08 100644 --- a/docs/gns3-copilot/context-window-management.md +++ b/docs/gns3-copilot/context-window-management.md @@ -324,3 +324,32 @@ except Exception as e: - `gns3server/agent/gns3_copilot/agent/context_manager.py` - Context management core logic - `gns3server/agent/gns3_copilot/agent/gns3_copilot.py` - LLM call node (StateGraph) - `gns3server/agent/gns3_copilot/agent/model_factory.py` - Model creation and tool binding + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/llm-model-configs-api.md b/docs/gns3-copilot/llm-model-configs-api.md index 7449e00f3..be7a27b04 100644 --- a/docs/gns3-copilot/llm-model-configs-api.md +++ b/docs/gns3-copilot/llm-model-configs-api.md @@ -884,3 +884,32 @@ HTTP 400 Bad Request "detail": "context_limit is required (unit: K tokens, e.g., 128 = 128K = 128,000 tokens). Please check your model provider's documentation for the current context window size and specify it in the configuration." } ``` + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md b/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md index 2bbc73f5f..ead926d9a 100644 --- a/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md +++ b/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md @@ -1204,3 +1204,32 @@ const exampleACEs = [ **Document Version**: 1.0 **Last Updated**: 2026-03-06 + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/enhance-user-me-endpoint.md b/docs/gns3-copilot/todo/enhance-user-me-endpoint.md index fa37d645b..d3f19c009 100644 --- a/docs/gns3-copilot/todo/enhance-user-me-endpoint.md +++ b/docs/gns3-copilot/todo/enhance-user-me-endpoint.md @@ -821,3 +821,32 @@ pools = {p.resource_pool_id: p for p in pools_result.scalars().all()} **Document Version**: 1.0 **Last Updated**: 2026-03-06 + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/hitl-implementation-plan.md b/docs/gns3-copilot/todo/hitl-implementation-plan.md index 9fc86a148..6b0499c17 100644 --- a/docs/gns3-copilot/todo/hitl-implementation-plan.md +++ b/docs/gns3-copilot/todo/hitl-implementation-plan.md @@ -1400,3 +1400,32 @@ If rollback is needed: **Document Version**: v1.0 **Created Date**: 2026-03-04 **Author**: GNS3 Development Team + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/multi-user-concurrency-control.md b/docs/gns3-copilot/todo/multi-user-concurrency-control.md index bbca6693e..8549e374e 100644 --- a/docs/gns3-copilot/todo/multi-user-concurrency-control.md +++ b/docs/gns3-copilot/todo/multi-user-concurrency-control.md @@ -576,3 +576,32 @@ async def test_concurrent_config_operations(): | Date | Change | |------|--------| | 2025-03-06 | Initial document creation | + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/orphan-tool-calls-recovery.md b/docs/gns3-copilot/todo/orphan-tool-calls-recovery.md index 057144ad0..e3878a651 100644 --- a/docs/gns3-copilot/todo/orphan-tool-calls-recovery.md +++ b/docs/gns3-copilot/todo/orphan-tool-calls-recovery.md @@ -449,3 +449,32 @@ log.info("After fix: tool_calls=%d", - [LangGraph Checkpointer Documentation](https://langchain-ai.github.io/langgraph/concepts/low_level/#checkpointer) - [LangGraph State Management](https://langchain-ai.github.io/langgraph/concepts/low_level/#state) - [GNS3-Copilot AI Chat API Design](../ai-chat-api-design.md) + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/runtime-agent-params.md b/docs/gns3-copilot/todo/runtime-agent-params.md index 7f7b9f8e6..d2aa06953 100644 --- a/docs/gns3-copilot/todo/runtime-agent-params.md +++ b/docs/gns3-copilot/todo/runtime-agent-params.md @@ -490,3 +490,32 @@ class AdvancedAgentControls(BaseModel): **Last Updated**: 2025-03-06 **Target Version**: TBD + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/runtime-llm-config-override.md b/docs/gns3-copilot/todo/runtime-llm-config-override.md new file mode 100644 index 000000000..0d435f8db --- /dev/null +++ b/docs/gns3-copilot/todo/runtime-llm-config-override.md @@ -0,0 +1,781 @@ +# Runtime LLM Config Override + +**Document Status**: Design Phase +**Priority**: Medium +**Created**: 2026-03-09 +**Related Docs**: +- [AI Chat API Design](../ai-chat-api-design.md) +- [LLM Model Configs API](../llm-model-configs-api.md) +- [User-Selectable Group Default Config](./user-selectable-group-default-config.md) + +--- + +## Table of Contents + +- [Problem Description](#problem-description) +- [Requirements Analysis](#requirements-analysis) +- [Solution Design](#solution-design) +- [Implementation Steps](#implementation-steps) +- [Code Changes Checklist](#code-changes-checklist) +- [Testing Plan](#testing-plan) +- [Risk Assessment](#risk-assessment) + +--- + +## Problem Description + +### Current Behavior + +Currently, the Chat API always uses the user's default LLM configuration from the database. Users cannot: +1. Select a different saved configuration for a specific request +2. Temporarily override certain parameters (e.g., use a different model, adjust temperature) for a single request + +### User Scenarios + +**Scenario 1: Quick Model Testing** +``` +User has multiple configs: +- "GPT-4o" (default) +- "Claude 3.5 Sonnet" +- "Gemini Pro" + +User wants to test the same prompt on Claude 3.5 without changing default +``` + +**Scenario 2: Temporary Parameter Adjustment** +``` +User's default config: +- model: "gpt-4o" +- temperature: 0.7 + +User wants to try a more creative response (temperature=1.2) for this request only +``` + +**Scenario 3: Cost Optimization** +``` +User's default config: +- model: "gpt-4o" (expensive) + +User wants to use "gpt-4o-mini" for this simple request +``` + +### Current Limitation + +**File**: `gns3server/api/routes/controller/chat.py:122` + +```python +# Always gets user's default config +llm_config = await get_user_llm_config_full(str(user_id), app) +``` + +No way to specify alternative config or override parameters at request time. + +--- + +## Requirements Analysis + +### Functional Requirements + +1. **Select Saved Configuration** + - User can specify `llm_config_id` to use a different saved config + - Must be a config owned by the user or inherited from their group + - Validation: If config_id is invalid or inaccessible, return error + +2. **Override LLM Parameters** + - Support temporary override of common LLM parameters: + - `model`: Model name (e.g., "gpt-4o", "claude-3-5-sonnet-20241022") + - `temperature`: Sampling temperature (0.0-2.0) + - `max_tokens`: Maximum tokens to generate + - `top_p`: Nucleus sampling parameter + - (Additional provider-specific parameters as needed) + - Overrides apply only to the current request + - Original config in database is NOT modified + +3. **Parameter Precedence** + ``` + Request Overrides > Database Config > Provider Defaults + ``` + +4. **Backward Compatibility** + - All new parameters are optional + - Existing requests without new parameters work unchanged + +### Non-Functional Requirements + +1. **Security** + - API key from selected config remains secure + - Users can only select their accessible configs + - Overrides are logged for audit + +2. **Performance** + - Minimal overhead for config retrieval and validation + - No database write for temporary overrides + +3. **Maintainability** + - Clear code structure for override logic + - Easy to add new overridable parameters in the future + +--- + +## Solution Design + +### API Schema Changes + +**File**: `gns3server/schemas/controller/chat.py` + +```python +class LLMConfigOverride(BaseModel): + """Temporary LLM configuration overrides for a single request.""" + + model: Optional[str] = Field( + None, + description="Override the model name (e.g., 'gpt-4o', 'claude-3-5-sonnet-20241022'). " + "Provider and API key still come from the selected or default config." + ) + temperature: Optional[float] = Field( + None, + ge=0.0, + le=2.0, + description="Override sampling temperature (0.0-2.0). " + "Lower values make output more deterministic, higher values more random." + ) + max_tokens: Optional[int] = Field( + None, + ge=1, + description="Override maximum tokens to generate in the response." + ) + top_p: Optional[float] = Field( + None, + ge=0.0, + le=1.0, + description="Override nucleus sampling parameter (0.0-1.0)." + ) + + +class ChatRequest(BaseModel): + """Chat request model.""" + + message: str = Field(..., description="User message content") + session_id: Optional[str] = Field(None, description="Session ID (auto-generated if not provided)") + stream: bool = Field(default=True, description="Enable streaming response") + + # NEW: LLM Configuration Selection + llm_config_id: Optional[str] = Field( + None, + description="LLM configuration ID to use for this request. " + "Must be a config owned by the user or inherited from their group. " + "If not provided, uses the user's default LLM config." + ) + + # NEW: Runtime Parameter Overrides + llm_config_override: Optional[LLMConfigOverride] = Field( + None, + description="Temporary overrides for LLM parameters. " + "These overrides apply only to this request and do not modify the stored config. " + "Overrides take precedence over the selected/default config values." + ) + + mode: Literal["text"] = Field(default="text", description="Interaction mode") +``` + +### Configuration Resolution Flow + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 1. API Layer (chat.py) │ +│ POST /v3/projects/{project_id}/chat/stream │ +│ ChatRequest { │ +│ message, │ +│ llm_config_id?, # Select config │ +│ llm_config_override?: { # Override params │ +│ model?, temperature?, max_tokens?, top_p? │ +│ } │ +│ } │ +└────────────────────────────┬────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ 2. Config Resolution (get_llm_config_for_request) │ +│ │ +│ if llm_config_id provided: │ +│ → Get specific config by ID │ +│ → Validate: user must have access (own or inherited group) │ +│ → If invalid: return 403 Forbidden │ +│ else: │ +│ → Get user's default config (current behavior) │ +│ │ +│ Decrypt API key from resolved config │ +│ Apply llm_config_override (if provided) │ +│ → Override fields: model, temperature, max_tokens, top_p │ +│ │ +│ Result: { │ +│ provider, api_key, model*, temperature*, max_tokens*, top_p*, ... │ +│ } │ +│ (* = overridden if provided) │ +└────────────────────────────┬────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ 3. Agent Execution (agent_service.py) │ +│ Set ContextVars with resolved and overridden config │ +│ Proceed with normal Agent flow │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### Implementation Details + +#### File: `gns3server/db/tasks.py` + +Add new function `get_llm_config_for_request`: + +```python +async def get_llm_config_for_request( + user_id: str, + app: FastAPI, + config_id: Optional[str] = None, + overrides: Optional[dict] = None +) -> Optional[dict]: + """ + Get LLM configuration for a specific request with optional overrides. + + Args: + user_id: User UUID + app: FastAPI application instance + config_id: Optional specific config ID to use + overrides: Optional dict of parameter overrides (model, temperature, etc.) + + Returns: + Dictionary with LLM configuration (with overrides applied) or None if not found. + + Raises: + ValueError: If config_id is specified but not accessible to user + """ + from uuid import UUID + from gns3server.db.repositories.llm_model_configs import LLMModelConfigsRepository + from gns3server.utils.encryption import decrypt, is_encrypted + + try: + user_uuid = UUID(user_id) if isinstance(user_id, str) else user_id + + async with AsyncSession(app.state._db_engine, expire_on_commit=False) as session: + repo = LLMModelConfigsRepository(session) + + # Step 1: Resolve base config + if config_id: + # User specified a config - validate access + config_uuid = UUID(config_id) if isinstance(config_id, str) else config_id + + # Get all accessible configs for user + effective = await repo.get_user_effective_configs( + user_uuid, + current_user_id=user_uuid, + current_user_is_superadmin=False + ) + + accessible_config_ids = {c["config_id"] for c in effective["configs"]} + + if config_uuid not in accessible_config_ids: + log.warning( + f"User {user_id} attempted to use inaccessible config {config_id}" + ) + raise ValueError(f"Config {config_id} is not accessible to user") + + # Get the config (bypass API key hiding since this is system-level) + config_record = await repo.get_user_config(config_uuid) + if not config_record: + log.error(f"Config {config_id} not found in database") + return None + + source = "user_selected" + + else: + # Use user's default config + result = await repo.get_user_effective_configs( + user_uuid, + current_user_id=user_uuid, + current_user_is_superadmin=False + ) + + if not result or not result.get("default_config"): + log.warning(f"No default LLM configuration found for user {user_id}") + return None + + default_config = result["default_config"] + config_id_str = default_config["config_id"] + config_record = await repo.get_user_config(UUID(config_id_str)) + + if not config_record: + log.error(f"Default config {config_id_str} not found in database") + return None + + source = "default" + + # Step 2: Decrypt API key + config_data = config_record.config.copy() + inherited_from_config_id = config_record.inherited_from_config_id + + # Handle shadow configs - get API key from parent + if inherited_from_config_id: + parent_config = await repo.get_group_config(inherited_from_config_id) + if parent_config and "api_key" in parent_config.config: + try: + encrypted_key = parent_config.config["api_key"] + if encrypted_key and is_encrypted(encrypted_key): + config_data["api_key"] = decrypt(encrypted_key) + else: + config_data["api_key"] = encrypted_key + except Exception as e: + log.error(f"Failed to decrypt inherited API key: {e}") + return None + else: + # Regular config - decrypt directly + if "api_key" in config_data and config_data["api_key"]: + try: + if is_encrypted(config_data["api_key"]): + config_data["api_key"] = decrypt(config_data["api_key"]) + except Exception as e: + log.error(f"Failed to decrypt API key: {e}") + return None + + # Step 3: Apply overrides + if overrides: + if overrides.get("model"): + config_data["model"] = overrides["model"] + log.info(f"Model override applied: {overrides['model']}") + if overrides.get("temperature") is not None: + config_data["temperature"] = overrides["temperature"] + log.info(f"Temperature override applied: {overrides['temperature']}") + if overrides.get("max_tokens") is not None: + config_data["max_tokens"] = overrides["max_tokens"] + log.info(f"Max tokens override applied: {overrides['max_tokens']}") + if overrides.get("top_p") is not None: + config_data["top_p"] = overrides["top_p"] + log.info(f"Top-p override applied: {overrides['top_p']}") + + # Step 4: Build final config dict + llm_config = { + "config_id": str(config_record.config_id), + "name": config_record.name, + "model_type": str(config_record.model_type), + "source": source, + "user_id": str(config_record.user_id) if config_record.user_id else None, + "group_id": str(config_record.group_id) if config_record.group_id else None, + "inherited_from": str(inherited_from_config_id) if inherited_from_config_id else None, + **config_data + } + + # Validate required fields + if not llm_config.get("provider"): + log.error(f"LLM config missing 'provider' field: {config_record.config_id}") + return None + + if not llm_config.get("model"): + log.error(f"LLM config missing 'model' field: {config_record.config_id}") + return None + + if not llm_config.get("api_key"): + log.error(f"LLM config missing 'api_key' field: {config_record.config_id}") + return None + + log.info( + f"Retrieved LLM config for user {user_id}: " + f"provider={llm_config.get('provider')}, model={llm_config.get('model')}, " + f"source={source}, overrides_applied={bool(overrides)}" + ) + + return llm_config + + except ValueError: + raise # Re-raise validation errors + except Exception as e: + log.error(f"Failed to retrieve LLM config for user {user_id}: {e}", exc_info=True) + return None +``` + +#### File: `gns3server/api/routes/controller/chat.py` + +Modify the stream endpoint to use new function: + +```python +@router.post("/stream", response_model=SkipValidation[ChatResponse]) +async def stream_chat( + project_id: str, + request: ChatRequest, + current_user: schemas.User = Depends(get_current_active_user), +): + """Stream chat responses from the GNS3 Copilot Agent.""" + + # ... existing project validation code ... + + # NEW: Resolve LLM config with overrides + overrides = None + if request.llm_config_override: + overrides = request.llm_config_override.model_dump(exclude_none=True) + + try: + llm_config = await get_llm_config_for_request( + user_id=str(current_user.user_id), + app=app, + config_id=request.llm_config_id, + overrides=overrides + ) + except ValueError as e: + raise HTTPException( + status_code=403, + detail=str(e) + ) + + if not llm_config: + raise HTTPException( + status_code=400, + detail="LLM configuration not found or not accessible. Please configure an LLM model first." + ) + + # ... rest of existing code with llm_config ... + + # Set ContextVars + set_current_jwt_token(jwt_token) + set_current_llm_config(llm_config) + + # ... continue with Agent flow ... +``` + +--- + +## Implementation Steps + +| Step | Task | File(s) | Difficulty | Priority | +|------|------|---------|------------|----------| +| 1 | Add `LLMConfigOverride` schema | `schemas/controller/chat.py` | ⭐ Low | P0 | +| 2 | Add `llm_config_id` and `llm_config_override` to `ChatRequest` | `schemas/controller/chat.py` | ⭐ Low | P0 | +| 3 | Implement `get_llm_config_for_request` function | `db/tasks.py` | ⭐⭐ Medium | P0 | +| 4 | Modify `stream_chat` endpoint to use new function | `api/routes/controller/chat.py` | ⭐ Low | P0 | +| 5 | Update API documentation | `docs/gns3-copilot/ai-chat-api-design.md` | ⭐ Low | P1 | +| 6 | Add unit tests for config resolution logic | `tests/` | ⭐⭐ Medium | P1 | +| 7 | Add integration tests for override scenarios | `tests/` | ⭐⭐ Medium | P2 | + +--- + +## Usage Examples + +### Example 1: Select Different Config + +```bash +# Use a specific saved config instead of default +curl -X POST http://localhost:3080/v3/projects/{project_id}/chat/stream \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "message": "Explain OSPF configuration", + "llm_config_id": "123e4567-e89b-12d3-a456-426614174000" + }' +``` + +### Example 2: Override Model Only + +```bash +# Use default config but with a different model +curl -X POST http://localhost:3080/v3/projects/{project_id}/chat/stream \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "message": "Configure OSPF on all routers", + "llm_config_override": { + "model": "gpt-4o-mini" + } + }' +``` + +### Example 3: Override Temperature + +```bash +# Use default config but with higher temperature for creativity +curl -X POST http://localhost:3080/v3/projects/{project_id}/chat/stream \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "message": "Write a creative network scenario", + "llm_config_override": { + "temperature": 1.2, + "top_p": 0.95 + } + }' +``` + +### Example 4: Select Config + Override Parameters + +```bash +# Use specific config and override multiple parameters +curl -X POST http://localhost:3080/v3/projects/{project_id}/chat/stream \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "message": "Analyze network topology", + "llm_config_id": "123e4567-e89b-12d3-a456-426614174000", + "llm_config_override": { + "model": "claude-3-5-sonnet-20241022", + "temperature": 0.3, + "max_tokens": 4096 + } + }' +``` + +### Example 5: Error Case - Inaccessible Config + +```bash +# Attempting to use another user's config returns 403 +curl -X POST http://localhost:3080/v3/projects/{project_id}/chat/stream \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "message": "Test", + "llm_config_id": "00000000-0000-0000-0000-000000000000" + }' + +# Response: +# { +# "detail": "Config 00000000-0000-0000-0000-000000000000 is not accessible to user" +# } +``` + +--- + +## Code Changes Checklist + +### Files to Modify + +| File Path | Change Type | Description | +|-----------|-------------|-------------| +| `gns3server/schemas/controller/chat.py` | Modify | Add `LLMConfigOverride` model and new fields to `ChatRequest` | +| `gns3server/db/tasks.py` | Add | Add `get_llm_config_for_request` function | +| `gns3server/api/routes/controller/chat.py` | Modify | Use `get_llm_config_for_request` with error handling | +| `docs/gns3-copilot/ai-chat-api-design.md` | Modify | Update API documentation with new parameters | + +### New Files + +| File Path | Description | +|-----------|-------------| +| N/A | No new files (all changes are modifications) | + +--- + +## Testing Plan + +### Unit Tests + +#### 1. Test `get_llm_config_for_request` + +- **Test 1.1**: Use default config (no config_id) + - Input: `config_id=None, overrides=None` + - Expected: Returns user's default config + +- **Test 1.2**: Use specific user config + - Input: Valid `config_id` owned by user + - Expected: Returns specified config + +- **Test 1.3**: Use inherited group config + - Input: Valid `config_id` from user's group + - Expected: Returns specified config with API key from parent + +- **Test 1.4**: Use inaccessible config + - Input: `config_id` from another user + - Expected: Raises `ValueError` + +- **Test 1.5**: Apply model override + - Input: `overrides={"model": "gpt-4o-mini"}` + - Expected: Returns config with `model="gpt-4o-mini"` + +- **Test 1.6**: Apply temperature override + - Input: `overrides={"temperature": 1.5}` + - Expected: Returns config with `temperature=1.5` + +- **Test 1.7**: Apply multiple overrides + - Input: `overrides={"model": "x", "temperature": 0.5, "max_tokens": 1000}` + - Expected: Returns config with all overrides applied + +- **Test 1.8**: Invalid config_id + - Input: Non-existent `config_id` + - Expected: Returns `None` + +### Integration Tests + +#### 1. API Endpoint Tests + +- **Test 1.1**: Request without new parameters (backward compatibility) + - Expected: Works exactly as before + +- **Test 1.2**: Request with `llm_config_id` only + - Expected: Uses specified config + +- **Test 1.3**: Request with `llm_config_override` only + - Expected: Uses default config with overrides + +- **Test 1.4**: Request with both `llm_config_id` and `llm_config_override` + - Expected: Uses specified config with overrides + +- **Test 1.5**: Request with inaccessible `llm_config_id` + - Expected: Returns 403 Forbidden + +- **Test 1.6**: Override validation (temperature out of range) + - Input: `temperature=3.0` (exceeds max 2.0) + - Expected: Returns 422 Validation Error + +#### 2. Agent Integration Tests + +- **Test 2.1**: Agent uses overridden config correctly + - Verify LLM is called with overridden parameters + +- **Test 2.2**: Multiple concurrent requests with different configs + - Verify no cross-contamination between requests + +--- + +## Risk Assessment + +### Technical Risks + +| Risk | Impact | Probability | Mitigation | +|------|--------|-------------|------------| +| Config retrieval performance degradation | Medium | Low | Cache frequently used configs, optimize queries | +| Override validation bypass | High | Low | Pydantic validation for all override fields | +| API key leakage in logs | High | Low | Ensure API key is never logged, use [REDACTED] | +| Incorrect config precedence | Medium | Low | Clear documentation and thorough testing | + +### Security Risks + +| Risk | Impact | Probability | Mitigation | +|------|--------|-------------|------------| +| User accessing another user's config | High | Low | Validate config accessibility before use | +| Privilege escalation via config_id | High | Low | Strict access control validation | +| API key exposure via override | Low | Low | API key cannot be overridden (not in schema) | + +### Compatibility Risks + +| Risk | Impact | Probability | Mitigation | +|------|--------|-------------|------------| +| Existing clients break | High | Low | All new fields are optional, default behavior unchanged | +| UI doesn't support new fields | Low | Medium | UI can ignore new fields, phased rollout | + +--- + +## Security Considerations + +### Access Control + +1. **Config Access Validation** + - User can only specify configs they own or inherited from their group + - Validation happens before API key decryption + - 403 Forbidden error for inaccessible configs + +2. **Immutable Fields** + - `api_key` cannot be overridden (not in `LLMConfigOverride`) + - `provider` cannot be overridden (requires different API key handling) + - Only safe parameters can be overridden + +3. **Audit Logging** + - Log all override operations with user_id, config_id, and override values + - Do not log API keys (use [REDACTED] placeholder) + +### Parameter Validation + +| Parameter | Validation | Rationale | +|-----------|------------|-----------| +| `llm_config_id` | Must be valid UUID, accessible to user | Prevent injection attacks | +| `model` | String, max length 255 | Prevent oversized strings | +| `temperature` | 0.0 ≤ value ≤ 2.0 | LLM API limits | +| `max_tokens` | ≥ 1 | Prevent negative/zero values | +| `top_p` | 0.0 ≤ value ≤ 1.0 | LLM API limits | + +--- + +## Future Enhancements + +### Phase 2 Features + +1. **Additional Override Parameters** + - `frequency_penalty`: Token frequency penalty + - `presence_penalty`: Token presence penalty + - `stop`: Stop sequences + - Provider-specific parameters (e.g., OpenAI functions) + +2. **Config Templates** + - Predefined override templates (e.g., "creative", "precise", "fast") + - Users can save and reuse override combinations + +3. **Usage Statistics** + - Track which configs are most commonly used + - Track which overrides are most commonly applied + - Provide insights for default config optimization + +4. **Config Recommendations** + - Suggest optimal config based on request content + - Auto-select cost-effective config for simple queries + +--- + +## Related Features + +- [User-Selectable Group Default Config](./user-selectable-group-default-config.md) - Setting default config +- [Runtime Agent Parameters](./runtime-agent-params.md) - Controlling Agent execution behavior +- [LLM Model Configs API](../llm-model-configs-api.md) - Managing saved configurations + +--- + +## References + +- [AI Chat API Design](../ai-chat-api-design.md) +- [Pydantic Field Validation](https://docs.pydantic.dev/latest/concepts/fields/) +- FastAPI Request Handling: https://fastapi.tiangolo.com/tutorial/body/ + +--- + +## Discussion Points + +### Open Questions + +1. **Should we allow `provider` override?** + - Pro: More flexibility (e.g., switch from OpenAI to Anthropic) + - Con: Requires different API key handling, more complex + - **Recommendation**: No - keep it simple for now + +2. **Should overrides be visible in response metadata?** + - Pro: User knows which config/overrides were used + - Con: Increases response size + - **Recommendation**: Add to session metadata, not SSE messages + +3. **Should we support parameter shortcuts?** + - Example: `"mode": "fast"` instead of specifying all parameters + - **Recommendation**: Future enhancement via templates + +--- + +**Document Version**: 1.0 +**Last Updated**: 2026-03-09 +**Target Version**: TBD + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) diff --git a/docs/gns3-copilot/todo/sse-interruption-and-agent-cancellation.md b/docs/gns3-copilot/todo/sse-interruption-and-agent-cancellation.md index 16000170a..80e051b83 100644 --- a/docs/gns3-copilot/todo/sse-interruption-and-agent-cancellation.md +++ b/docs/gns3-copilot/todo/sse-interruption-and-agent-cancellation.md @@ -238,3 +238,32 @@ async def stream_chat(request_id: str, ...): 2. [ ] Add client disconnect detection in yield loop 3. [ ] Document frontend handling for incomplete messages 4. [ ] Test reconnection scenario with tool_call interruption + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/tool-response-format-standard.md b/docs/gns3-copilot/todo/tool-response-format-standard.md index ba891e925..895544230 100644 --- a/docs/gns3-copilot/todo/tool-response-format-standard.md +++ b/docs/gns3-copilot/todo/tool-response-format-standard.md @@ -213,3 +213,32 @@ When the format changes, update the `metadata.version` field, and the frontend a - Implementation: `gns3server/agent/gns3_copilot/utils/parse_tool_content.py` - Message conversion: `gns3server/agent/gns3_copilot/utils/message_converters.py` - Tool examples: `gns3server/agent/gns3_copilot/tools_v2/` + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/user-selectable-group-default-config.md b/docs/gns3-copilot/todo/user-selectable-group-default-config.md index 0404830ab..ed3f04ae6 100644 --- a/docs/gns3-copilot/todo/user-selectable-group-default-config.md +++ b/docs/gns3-copilot/todo/user-selectable-group-default-config.md @@ -928,3 +928,32 @@ Add `inherited_from` field description in response schema section: **Document Version**: 1.0 **Last Updated**: 2026-03-06 + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/todo/vision-topology-creation.md b/docs/gns3-copilot/todo/vision-topology-creation.md new file mode 100644 index 000000000..feaaf6ef8 --- /dev/null +++ b/docs/gns3-copilot/todo/vision-topology-creation.md @@ -0,0 +1,1009 @@ +# Vision-Based Topology Creation + +**Document Status**: Design Phase +**Priority**: High +**Created**: 2026-03-09 +**Related Docs**: +- [AI Chat API Design](../ai-chat-api-design.md) +- [GNS3 Templates API](../../compute/templates_api.md) +- [FlowNet-Lab Vision Recognition](../../../../FlowNet-Lab/backend/api/v1/vision.py) + +--- + +## Table of Contents + +- [Overview](#overview) +- [Problem Description](#problem-description) +- [Requirements Analysis](#requirements-analysis) +- [Solution Design](#solution-design) +- [Implementation Steps](#implementation-steps) +- [Code Changes Checklist](#code-changes-checklist) +- [Testing Plan](#testing-plan) +- [Risk Assessment](#risk-assessment) + +--- + +## Overview + +This feature enables users to create GNS3 topologies by uploading network topology images. The system uses vision language models (VLM) to analyze the image and generate structured topology data, then uses LLM to map the recognized devices to GNS3 templates and create the topology automatically. + +### Workflow + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 1. User uploads topology image (base64 or file) │ +└────────────────────────────┬────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ 2. Vision Model Analysis (Qwen-VL / GPT-4V / Claude 3.5 Sonnet) │ +│ - Analyze image structure │ +│ - Identify devices (routers, switches, hosts, etc.) │ +│ - Identify connections between devices │ +│ - Extract interface and IP information (if visible) │ +│ - Return structured JSON topology │ +└────────────────────────────┬────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ 3. LLM Processing & Template Mapping │ +│ - Get available GNS3 device templates from project │ +│ - Map recognized device types to appropriate GNS3 templates │ +│ - Handle user preferences (specific device models, etc.) │ +│ - Generate deployment plan │ +└────────────────────────────┬────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ 4. Topology Creation via Agent Tools │ +│ - Create nodes using mapped templates │ +│ - Create links between nodes │ +│ - Configure interfaces (if IP info available) │ +│ - Optional: Auto-start nodes │ +└────────────────────────────┬────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ 5. Return Result │ +│ - Created topology information │ +│ - Node list with template mappings │ +│ - Link list │ +│ - Configuration summary │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Problem Description + +### Current Limitations + +1. **Manual Topology Creation**: Users must manually create nodes and links in GNS3 UI +2. **Time-Consuming**: Creating complex topologies with many devices is tedious +3. **Error-Prone**: Manual configuration can lead to mistakes (wrong connections, missing interfaces) +4. **No Visual Import**: Existing topology diagrams cannot be automatically imported + +### User Scenarios + +**Scenario 1: Lab Replication** +``` +User has a network topology diagram from: +- Textbook or course material +- Network documentation +- Exam scenario +- Online reference + +User wants to quickly recreate this topology in GNS3 for practice +``` + +**Scenario 2: Migration from Other Tools** +``` +User has topology designs from: +- Packet Tracer +- VIRL +- Network visualization tools +- Drawn diagrams (Visio, draw.io) + +User wants to import into GNS3 +``` + +**Scenario 3: Rapid Prototyping** +``` +Network architect designs topology in visual tool +Wants to quickly test in GNS3 without manual recreation +``` + +--- + +## Requirements Analysis + +### Functional Requirements + +1. **Image Input Support** + - Accept base64 encoded image data + - Support common image formats (PNG, JPG, JPEG, GIF, BMP, WebP) + - Maximum image size: 10MB (configurable) + +2. **Vision Model Support** + - Support multiple vision language models: + - Qwen-VL (qwen-vl-max, qwen3-vl-plus, qwen3-vl-flash) + - OpenAI GPT-4V / GPT-4o + - Anthropic Claude 3.5 Sonnet (vision capable) + - User can select which model to use + - Graceful fallback if model unavailable + +3. **Topology Recognition Output** + Structured JSON format: + ```json + { + "topology_name": "Topology name", + "description": "Brief description", + "devices": [ + { + "id": "unique_id", + "name": "device_name", + "type": "router|switch|host|server|cloud|firewall", + "model": "device_model_if_visible", + "position": {"x": 0, "y": 0} + } + ], + "links": [ + { + "id": "unique_id", + "source_device": "device_name", + "source_interface": "interface_name", + "target_device": "device_name", + "target_interface": "interface_name", + "link_type": "ethernet|serial" + } + ], + "interfaces": [ + { + "device": "device_name", + "interface": "interface_name", + "ip_address": "ip_address", + "subnet_mask": "subnet_mask" + } + ], + "summary": { + "total_devices": 0, + "total_links": 0, + "device_types": {"router": 0, "switch": 0, "host": 0, "other": 0} + } + } + ``` + +4. **Template Mapping** + - Automatically map recognized device types to GNS3 templates + - User can override template mappings + - Support user-specified device model preferences + - Handle cases where suitable template not found + +5. **Topology Creation** + - Create nodes using mapped templates + - Create links between nodes + - Preserve relative device positions (if available) + - Optional: Auto-start nodes after creation + +6. **User Preferences** + - Specify preferred device models per device type + - Choose whether to auto-start nodes + - Configure default link types + +### Non-Functional Requirements + +1. **Performance** + - Vision analysis should complete within 30 seconds + - Topology creation should complete within 60 seconds (for ~20 devices) + +2. **Reliability** + - Handle vision model errors gracefully + - Validate recognized topology before creation + - Provide clear error messages + +3. **Security** + - Validate image size and format + - Sanitize file names + - Rate limiting to prevent abuse + +4. **Extensibility** + - Easy to add new vision models + - Support custom device type mappings + - Pluggable template selection strategy + +--- + +## Solution Design + +### Architecture + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ API Layer │ +│ ┌────────────────────────────────────────────────────────────────────┐ │ +│ │ POST /v3/projects/{project_id}/chat/vision-topology │ │ +│ │ - Accepts image (base64 or file reference) │ │ +│ │ - Accepts optional preferences (device models, auto-start, etc.) │ │ +│ └────────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Vision Model Layer │ +│ ┌────────────────────────────────────────────────────────────────────┐ │ +│ │ VisionModelFactory │ │ +│ │ - Creates appropriate vision model based on config │ │ +│ │ - Supports: Qwen-VL, OpenAI, Anthropic │ │ +│ └────────────────────────────────────────────────────────────────────┘ │ +│ ┌────────────────────────────────────────────────────────────────────┐ │ +│ │ BaseVisionModel (abstract) │ │ +│ │ - recognize_topology(image_base64, prompt) -> dict │ │ +│ │ │ │ +│ │ QwenVisionModel │ │ +│ │ OpenAIVisionModel │ │ +│ │ AnthropicVisionModel │ │ +│ └────────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Agent Layer │ +│ ┌────────────────────────────────────────────────────────────────────┐ │ +│ │ Vision Topology Agent (LangGraph) │ │ +│ │ - Analyzes recognized topology │ │ +│ │ - Gets available GNS3 templates │ │ +│ │ - Maps device types to templates │ │ +│ │ - Generates creation plan │ │ +│ │ - Executes creation via tools │ │ +│ └────────────────────────────────────────────────────────────────────┘ │ +│ ┌────────────────────────────────────────────────────────────────────┐ │ +│ │ Tools: │ │ +│ │ - get_gns3_templates (existing) │ │ +│ │ - create_node (existing) │ │ +│ │ - create_link (existing) │ │ +│ │ - start_node (existing) │ │ +│ │ - map_device_to_template (new) │ │ +│ └────────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ GNS3 Controller API │ +│ - Creates nodes in project │ +│ - Creates links between nodes │ +│ - Configures interfaces │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### API Design + +#### New Endpoint + +**POST** `/v3/projects/{project_id}/vision-topology` + +**Request Body:** +```json +{ + "image_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", + "custom_prompt": "Optional custom prompt for vision model", + "preferences": { + "vision_model": "qwen-vl-max", + "device_models": { + "router": "c3740", + "switch": "vEOS", + "host": "vpcs", + "server": "docker-alpine" + }, + "auto_start": false, + "default_link_type": "ethernet" + } +} +``` + +**Response:** +```json +{ + "recognized_topology": { + "topology_name": "OSPF Three Router Topology", + "description": "Three routers connected in triangle", + "devices": [...], + "links": [...], + "interfaces": [...], + "summary": {...} + }, + "template_mappings": { + "R1": {"template_id": "c3740", "template_name": "Cisco 3740"}, + "R2": {"template_id": "c3740", "template_name": "Cisco 3740"}, + "R3": {"template_id": "c3740", "template_name": "Cisco 3740"} + }, + "created_nodes": [ + {"node_id": "...", "name": "R1", "template_id": "...", "position": {"x": 100, "y": 100}}, + ... + ], + "created_links": [ + {"link_id": "...", "source_node": "...", "target_node": "..."}, + ... + ], + "configuration_summary": { + "total_nodes_created": 3, + "total_links_created": 3, + "nodes_started": 0 + } +} +``` + +#### Alternative: Integrate with Chat API + +**POST** `/v3/projects/{project_id}/chat/vision` + +Same endpoint as `/stream`, but accepts `image_base64` field: + +```json +{ + "message": "Create this topology in GNS3", + "image_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", + "session_id": "optional-session-id", + "preferences": { + "device_models": {...} + } +} +``` + +Returns SSE stream with: +- `vision_start`: Vision analysis started +- `vision_progress`: Analysis progress updates +- `vision_result`: Recognized topology data +- `creation_start`: Topology creation started +- `node_created`: Individual node creation events +- `link_created`: Individual link creation events +- `done`: Creation complete + +### Component Design + +#### 1. Vision Model Layer + +**File**: `gns3server/agent/gns3_copilot/vision/models.py` + +```python +from abc import ABC, abstractmethod +from typing import Dict, Any, Optional + +class BaseVisionModel(ABC): + """Abstract base class for vision models.""" + + def __init__(self, api_key: str, model_name: str): + self.api_key = api_key + self.model_name = model_name + + @abstractmethod + async def recognize_topology( + self, + image_base64: str, + prompt: Optional[str] = None + ) -> Dict[str, Any]: + """ + Recognize network topology from image. + + Args: + image_base64: Base64 encoded image or data URL + prompt: Optional custom prompt + + Returns: + Dictionary with topology data (devices, links, interfaces, summary) + + Raises: + RuntimeError: If recognition fails + """ + pass + + +class QwenVisionModel(BaseVisionModel): + """Qwen-VL vision model implementation.""" + + async def recognize_topology( + self, + image_base64: str, + prompt: Optional[str] = None + ) -> Dict[str, Any]: + # Implementation using DashScope SDK + # (migrated from FlowNet-Lab) + pass + + +class OpenAIVisionModel(BaseVisionModel): + """OpenAI GPT-4V / GPT-4o vision model implementation.""" + + async def recognize_topology( + self, + image_base64: str, + prompt: Optional[str] = None + ) -> Dict[str, Any]: + # Implementation using OpenAI SDK + pass + + +class AnthropicVisionModel(BaseVisionModel): + """Anthropic Claude 3.5 Sonnet vision model implementation.""" + + async def recognize_topology( + self, + image_base64: str, + prompt: Optional[str] = None + ) -> Dict[str, Any]: + # Implementation using Anthropic SDK + pass + + +class VisionModelFactory: + """Factory for creating vision models.""" + + @staticmethod + def create_model( + provider: str, + api_key: str, + model_name: Optional[str] = None + ) -> BaseVisionModel: + """ + Create a vision model instance. + + Args: + provider: Model provider (qwen, openai, anthropic) + api_key: API key for the provider + model_name: Specific model name (optional, uses default if None) + + Returns: + BaseVisionModel instance + + Raises: + ValueError: If provider is not supported + """ + models = { + "qwen": (QwenVisionModel, model_name or "qwen3-vl-plus"), + "openai": (OpenAIVisionModel, model_name or "gpt-4o"), + "anthropic": (AnthropicVisionModel, model_name or "claude-3-5-sonnet-20241022"), + } + + if provider not in models: + raise ValueError(f"Unsupported vision model provider: {provider}") + + model_class, default_model = models[provider] + return model_class(api_key, model_name or default_model) +``` + +#### 2. Vision Topology Agent + +**File**: `gns3server/agent/gns3_copilot/agent/vision_topology_agent.py` + +```python +from langgraph.graph import StateGraph, END +from typing import Dict, Any, List + +class VisionTopologyAgent: + """Agent for creating GNS3 topologies from vision recognition results.""" + + def __init__(self, project_id: str, compute_service): + self.project_id = project_id + self.compute_service = compute_service + + async def create_topology_from_vision( + self, + recognized_topology: Dict[str, Any], + preferences: Dict[str, Any] + ) -> Dict[str, Any]: + """ + Create GNS3 topology from recognized vision data. + + Args: + recognized_topology: Topology data from vision model + preferences: User preferences (device models, auto-start, etc.) + + Returns: + Creation result with nodes, links, and summary + """ + # Step 1: Get available templates + templates = await self._get_available_templates() + + # Step 2: Map devices to templates + device_mappings = await self._map_devices_to_templates( + recognized_topology["devices"], + templates, + preferences.get("device_models", {}) + ) + + # Step 3: Create nodes + created_nodes = [] + for device in recognized_topology["devices"]: + mapping = device_mappings[device["name"]] + node = await self._create_node(device, mapping) + created_nodes.append(node) + + # Step 4: Create links + created_links = [] + for link in recognized_topology["links"]: + link_result = await self._create_link(link, created_nodes) + created_links.append(link_result) + + # Step 5: Optionally start nodes + if preferences.get("auto_start", False): + await self._start_nodes(created_nodes) + + return { + "recognized_topology": recognized_topology, + "template_mappings": device_mappings, + "created_nodes": created_nodes, + "created_links": created_links, + "configuration_summary": { + "total_nodes_created": len(created_nodes), + "total_links_created": len(created_links), + "nodes_started": len(created_nodes) if preferences.get("auto_start") else 0 + } + } + + async def _get_available_templates(self) -> Dict[str, Any]: + """Get available GNS3 templates for the project.""" + # Use existing GNS3 API + pass + + async def _map_devices_to_templates( + self, + devices: List[Dict[str, Any]], + templates: Dict[str, Any], + user_preferences: Dict[str, str] + ) -> Dict[str, Dict[str, str]]: + """ + Map recognized devices to GNS3 templates. + + Args: + devices: List of recognized devices + templates: Available GNS3 templates + user_preferences: User's preferred device models + + Returns: + Mapping of device names to template IDs + """ + # Use LLM to intelligently map device types to templates + # Consider user preferences, available templates, device types + pass + + async def _create_node( + self, + device: Dict[str, Any], + template_mapping: Dict[str, str] + ) -> Dict[str, Any]: + """Create a GNS3 node from device and template mapping.""" + # Use existing GNS3 create node API + pass + + async def _create_link( + self, + link: Dict[str, Any], + nodes: List[Dict[str, Any]] + ) -> Dict[str, Any]: + """Create a GNS3 link between nodes.""" + # Use existing GNS3 create link API + pass + + async def _start_nodes(self, nodes: List[Dict[str, Any]]): + """Start all nodes.""" + # Use existing GNS3 start node API + pass +``` + +#### 3. API Endpoint + +**File**: `gns3server/api/routes/controller/vision.py` + +```python +from fastapi import APIRouter, HTTPException, Depends +from pydantic import BaseModel + +router = APIRouter(tags=["vision"]) + +class VisionTopologyRequest(BaseModel): + """Request model for vision-based topology creation.""" + image_base64: str + custom_prompt: Optional[str] = None + preferences: Optional[Dict[str, Any]] = None + + +@router.post("/vision-topology") +async def create_topology_from_vision( + project_id: str, + request: VisionTopologyRequest, + current_user = Depends(get_current_active_user) +): + """ + Create GNS3 topology from network topology image. + + Accepts a base64 encoded image and automatically creates + the topology using vision recognition and Agent tools. + """ + try: + # Step 1: Initialize vision model + vision_model = VisionModelFactory.create_model( + provider=request.preferences.get("vision_model", "qwen"), + api_key=await _get_vision_api_key(current_user, request.preferences), + model_name=request.preferences.get("model_name") + ) + + # Step 2: Recognize topology + recognized_topology = await vision_model.recognize_topology( + image_base64=request.image_base64, + prompt=request.custom_prompt + ) + + # Step 3: Create topology via agent + agent = VisionTopologyAgent(project_id, compute_service) + result = await agent.create_topology_from_vision( + recognized_topology=recognized_topology, + preferences=request.preferences or {} + ) + + return result + + except Exception as e: + logger.error(f"Failed to create topology from vision: {e}") + raise HTTPException(status_code=500, detail=str(e)) +``` + +### Template Mapping Strategy + +#### Default Device Type Mappings + +| Recognized Type | Default GNS3 Template | Alternative Templates | +|-----------------|----------------------|----------------------| +| router | c3740 (Cisco 3740) | c7200, vIOS-L2 | +| switch | vEOS (VeOS) | vIOS-L2, OVS | +| host / PC | vpcs | docker-alpine | +| server | docker-alpine | docker-ubuntu | +| firewall | asav | none | +| cloud | cloud | none | + +#### LLM-Based Template Selection + +For more intelligent mapping: + +``` +Prompt to LLM: +""" +Given the following information: + +1. Recognized device: {name}, type: {type}, model: {model_if_visible} +2. Available GNS3 templates: {list_of_available_templates} +3. User preferences: {user_preferred_models} + +Select the most appropriate template and explain reasoning. + +Return JSON: +{ + "template_id": "...", + "template_name": "...", + "reasoning": "Why this template was selected" +} +""" +``` + +### Detailed Deployment Workflow (Based on FlowNet-Lab) + +#### Step-by-Step Process + +``` +1. Analyze Vision Result + ├─ Extract topology name + ├─ Identify all devices (names, types, models) + ├─ Identify all connections + └─ Note any special requirements + +2. Check Existing Projects + └─ Call list_gns3_projects to avoid duplicates + +3. Get Available Templates + └─ Call get_gns3_templates to see what's available + └─ Returns: [{"name": "...", "template_id": "...", "template_type": "..."}, ...] + +4. Map Devices to Templates + ├─ Use user preferences if specified + ├─ Use default mappings for recognized types + └─ Fallback to LLM-assisted selection + +5. Create All Nodes (Single Batch Call) + ├─ Use create_gns3_node with all nodes at once + ├─ Position nodes in grid layout (min 250px apart) + └─ Example positions: + (-400, -200) (-100, -200) (200, -200) + (-400, 0) (-100, 0) (200, 0) + (-400, 200) (-100, 200) (200, 200) + +6. Read Topology for Port Names + ├─ Call gns3_topology_reader with project_id + ├─ Extract actual port names from created nodes + └─ CRITICAL: Port names vary by template + └─ Cisco: Ethernet0/0, GigabitEthernet0/0 + └─ VPCS: Ethernet0 + └─ Docker: eth0, eth1 + +7. Update Node Names + └─ Call update_gns3_node_name to assign meaningful names (R1, R2, SW1, PC1) + +8. Create Links Using Actual Port Names + ├─ Call create_gns3_link for each connection + ├─ Use port names from topology reader (Step 6) + └─ NEVER guess port names - always use topology data + +9. Optionally Start Nodes + └─ Call start_gns3_node_quick to send start commands +``` + +#### Critical Deployment Rules + +1. **Always get templates first** before creating nodes +2. **Create all nodes in one call** for efficiency +3. **Get topology before creating links** to obtain actual port names +4. **Position nodes properly** - minimum 250 pixels apart +5. **Use actual port names from topology** when creating links: + - Port names vary by template type + - Examples: Ethernet0/0, GigabitEthernet0/0, eth0 + - Never guess - always use topology data +6. **Match device types to templates correctly** + +#### Node Positioning Strategy + +Grid layout pattern from FlowNet-Lab: + +```python +def calculate_node_positions(device_count): + """Calculate grid positions for nodes with minimum 250px spacing.""" + positions = [] + cols = min(4, device_count) # Max 4 columns + x_offset = 300 # 250px spacing + margin + y_offset = 200 # Vertical spacing + + start_x = -(cols - 1) * x_offset // 2 + start_y = -((device_count + cols - 1) // cols - 1) * y_offset // 2 + + for i, device in enumerate(devices): + row = i // cols + col = i % cols + x = start_x + col * x_offset + y = start_y + row * y_offset + positions.append({"x": x, "y": y}) + + return positions +``` + +--- + +## Implementation Steps + +| Phase | Step | Task | File(s) | Difficulty | Priority | +|-------|------|------|---------|------------|----------| +| 1 | 1.1 | Create base vision model classes | `agent/gns3_copilot/vision/models.py` | ⭐⭐ Medium | P0 | +| 1 | 1.2 | Implement QwenVisionModel | `agent/gns3_copilot/vision/models.py` | ⭐⭐ Medium | P0 | +| 1 | 1.3 | Implement OpenAIVisionModel | `agent/gns3_copilot/vision/models.py` | ⭐⭐ Medium | P1 | +| 1 | 1.4 | Implement AnthropicVisionModel | `agent/gns3_copilot/vision/models.py` | ⭐⭐ Medium | P1 | +| 2 | 2.1 | Create VisionTopologyAgent | `agent/gns3_copilot/agent/vision_topology_agent.py` | ⭐⭐⭐ High | P0 | +| 2 | 2.2 | Implement template mapping logic | `agent/gns3_copilot/agent/vision_topology_agent.py` | ⭐⭐⭐ High | P0 | +| 2 | 2.3 | Implement node/link creation | `agent/gns3_copilot/agent/vision_topology_agent.py` | ⭐⭐ Medium | P0 | +| 3 | 3.1 | Create API endpoint | `api/routes/controller/vision.py` | ⭐⭐ Medium | P0 | +| 3 | 3.2 | Add request/response schemas | `schemas/controller/vision.py` | ⭐ Low | P0 | +| 3 | 3.3 | Integrate with existing auth | `api/routes/controller/vision.py` | ⭐ Low | P0 | +| 4 | 4.1 | Add vision API key to LLM config | `db/models/llm_model_configs.py` | ⭐⭐ Medium | P1 | +| 4 | 4.2 | Update user config UI | (Frontend) | ⭐⭐⭐ High | P2 | +| 5 | 5.1 | Add unit tests | `tests/test_vision_models.py` | ⭐⭐ Medium | P1 | +| 5 | 5.2 | Add integration tests | `tests/test_vision_topology.py` | ⭐⭐⭐ High | P2 | +| 6 | 6.1 | Update API documentation | `docs/gns3-copilot/` | ⭐ Low | P1 | + +--- + +## Code Migration from FlowNet-Lab + +### Files to Migrate + +| FlowNet-Lab File | gns3-server Destination | Modifications Needed | +|------------------|------------------------|---------------------| +| `src/gns3_copilot/agent/qwen_vision_model.py` | `agent/gns3_copilot/vision/models.py` | Refactor into class, add async support | +| `backend/api/v1/vision.py` | `api/routes/controller/vision.py` | Adapt to GNS3 architecture, add Agent integration | +| `src/gns3_copilot/agent/model_factory.py` | `agent/gns3_copilot/vision/__init__.py` | Update factory pattern | + +### Key Modifications + +1. **Remove Dependencies** + - FlowNet-Lab specific config loading + - Custom logging setup (use gns3server logger) + +2. **Add Dependencies** + - GNS3 Controller API client + - GNS3 database models + - Existing Agent tools + +3. **Update Configuration** + - Use gns3server's config system + - Store vision API keys in user LLM config + +4. **Add Error Handling** + - GNS3-specific error codes + - Integration with GNS3 project status checks + +--- + +## Testing Plan + +### Unit Tests + +#### 1. Vision Model Tests + +- **Test 1.1**: Qwen-VL model initialization + - Valid API key → success + - Invalid API key → error + - Missing API key → error + +- **Test 1.2**: Topology recognition + - Valid topology image → structured JSON + - Invalid image → graceful error + - Malformed JSON response → error handling + +#### 2. Template Mapping Tests + +- **Test 2.1**: Default template mapping + - Router → c3740 + - Switch → vEOS + - Host → vpcs + +- **Test 2.2**: User preference override + - User prefers different router model → use preference + +- **Test 2.3**: Unknown device type + - Unknown type → default or error + +#### 3. Agent Tests + +- **Test 3.1**: Node creation + - Single device → single node created + - Multiple devices → multiple nodes created + +- **Test 3.2**: Link creation + - Valid link → link created between nodes + +- **Test 3.3**: Full topology + - 3 routers, 3 links → complete topology created + +### Integration Tests + +#### 1. End-to-End Tests + +- **Test 1.1**: Simple topology + - 2 routers, 1 link → verify creation + +- **Test 1.2**: Complex topology + - 5+ devices, multiple links → verify creation + +- **Test 1.3**: With IP configuration + - Topology with visible IPs → verify interface config + +#### 2. Error Handling Tests + +- **Test 2.1**: Invalid image + - Corrupted base64 → 400 error + +- **Test 2.2**: Project not opened + - Closed project → 403 error + +- **Test 2.3**: Vision model failure + - API error → graceful degradation + +### Performance Tests + +- **Test 1**: Vision analysis time + - Should complete within 30 seconds + +- **Test 2**: Topology creation time + - 20 devices should create within 60 seconds + +--- + +## Risk Assessment + +### Technical Risks + +| Risk | Impact | Probability | Mitigation | +|------|--------|-------------|------------| +| Vision model API rate limits | High | Medium | Implement rate limiting, queue system | +| Poor recognition accuracy | High | Medium | Support multiple vision models, user verification step | +| Template mapping failures | Medium | Medium | LLM-assisted mapping, user override options | +| Large image handling | Medium | Low | Size limits, image optimization | +| Vision API key management | High | Low | Encrypt storage, per-user keys | + +### Business Risks + +| Risk | Impact | Probability | Mitigation | +|------|--------|-------------|------------| +| User expectation mismatch | High | Medium | Clear documentation, example images | +| Cost of vision APIs | Medium | Medium | Usage tracking, cost warnings | +| Complex topology failures | Medium | High | Incremental creation, rollback support | + +--- + +## Future Enhancements + +### Phase 2 Features + +1. **Multi-Image Support** + - Stitch multiple images together + - Handle multi-page diagrams + +2. **Handwriting Recognition** + - Read handwritten labels and notes + - Extract configuration commands + +3. **Optical Character Recognition (OCR)** + - Extract IP addresses, subnet masks + - Read configuration snippets + +4. **Interactive Verification** + - Show recognized topology for user confirmation + - Allow manual corrections before creation + +5. **Template Suggestions** + - Suggest alternative templates + - Show compatibility warnings + +6. **Configuration Generation** + - Generate basic device configurations + - Apply common network protocols + +### Phase 3 Features + +1. **Topology Comparison** + - Compare created topology with original image + - Highlight differences + +2. **Auto-Configuration** + - Configure routing protocols based on topology + - Set up IP addressing schemes + +3. **Learning from User Corrections** + - Learn from user template preference changes + - Improve mapping suggestions over time + +--- + +## References + +- [FlowNet-Lab Vision Recognition](../../../../FlowNet-Lab/backend/api/v1/vision.py) +- [Qwen-VL Documentation](https://help.aliyun.com/zh/dashscope/developer-reference/vl-plus-api) +- [OpenAI Vision API](https://platform.openai.com/docs/guides/vision) +- [Anthropic Claude Vision](https://docs.anthropic.com/claude/docs/vision) +- [GNS3 Templates API](../../compute/templates_api.md) + +--- + +**Document Version**: 1.0 +**Last Updated**: 2026-03-09 +**Target Version**: TBD + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) diff --git a/docs/gns3-copilot/troubleshooting/datetime-timezone-issue.md b/docs/gns3-copilot/troubleshooting/datetime-timezone-issue.md index 8ebb5061d..8af547b8c 100644 --- a/docs/gns3-copilot/troubleshooting/datetime-timezone-issue.md +++ b/docs/gns3-copilot/troubleshooting/datetime-timezone-issue.md @@ -149,3 +149,32 @@ class Base: - Backend: `gns3server/api/server.py` - Backend: `gns3server/db/models/base.py` - Schemas: `gns3server/schemas/controller/base.py` + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/docs/gns3-copilot/troubleshooting/force-kill-residual-processes.md b/docs/gns3-copilot/troubleshooting/force-kill-residual-processes.md index 217d2d539..c4a60ec07 100644 --- a/docs/gns3-copilot/troubleshooting/force-kill-residual-processes.md +++ b/docs/gns3-copilot/troubleshooting/force-kill-residual-processes.md @@ -148,3 +148,32 @@ gns3server - [ ] Add process health check mechanism - [ ] Implement more robust port and ID reuse logic - [ ] Add residual process detection and warnings + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) + diff --git a/gns3server/agent/gns3_copilot/__init__.py b/gns3server/agent/gns3_copilot/__init__.py index ecbb76ca1..682ee1ebf 100644 --- a/gns3server/agent/gns3_copilot/__init__.py +++ b/gns3server/agent/gns3_copilot/__init__.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # @@ -39,6 +39,6 @@ try: except Exception: __version__ = "unknown" -__author__ = "Guobin Yue" +__author__ = "Yue Guobin (岳国宾)" __description__ = "AI-powered network automation assistant for GNS3" __url__ = "https://github.com/yueguobin/gns3-copilot" diff --git a/gns3server/agent/gns3_copilot/agent/__init__.py b/gns3server/agent/gns3_copilot/agent/__init__.py index 57c67d8e8..f72bc8b6e 100644 --- a/gns3server/agent/gns3_copilot/agent/__init__.py +++ b/gns3server/agent/gns3_copilot/agent/__init__.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # @@ -41,7 +41,7 @@ try: except Exception: __version__ = "unknown" -__author__ = "Guobin Yue" +__author__ = "Yue Guobin (岳国宾)" __description__ = "AI-powered network automation assistant for GNS3" __url__ = "https://github.com/yueguobin/gns3-copilot" diff --git a/gns3server/agent/gns3_copilot/agent/context_manager.py b/gns3server/agent/gns3_copilot/agent/context_manager.py index 5f1901a13..fccbb03c9 100644 --- a/gns3server/agent/gns3_copilot/agent/context_manager.py +++ b/gns3server/agent/gns3_copilot/agent/context_manager.py @@ -2,8 +2,8 @@ # # GNS3-Copilot - AI-powered Network Lab Assistant for GNS3 # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # This file is part of GNS3-Copilot project. # diff --git a/gns3server/agent/gns3_copilot/agent/gns3_copilot.py b/gns3server/agent/gns3_copilot/agent/gns3_copilot.py index 587653eeb..91fce3b99 100644 --- a/gns3server/agent/gns3_copilot/agent/gns3_copilot.py +++ b/gns3server/agent/gns3_copilot/agent/gns3_copilot.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/agent/model_factory.py b/gns3server/agent/gns3_copilot/agent/model_factory.py index 4b906db6f..ad5445b72 100644 --- a/gns3server/agent/gns3_copilot/agent/model_factory.py +++ b/gns3server/agent/gns3_copilot/agent/model_factory.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/agent_service.py b/gns3server/agent/gns3_copilot/agent_service.py index aad466361..d42187477 100644 --- a/gns3server/agent/gns3_copilot/agent_service.py +++ b/gns3server/agent/gns3_copilot/agent_service.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/chat_sessions_repository.py b/gns3server/agent/gns3_copilot/chat_sessions_repository.py index e5908ddcd..af07f4db7 100644 --- a/gns3server/agent/gns3_copilot/chat_sessions_repository.py +++ b/gns3server/agent/gns3_copilot/chat_sessions_repository.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/config/forbidden_commands.txt b/gns3server/agent/gns3_copilot/config/forbidden_commands.txt index 71c3a32f4..1bc9116e2 100644 --- a/gns3server/agent/gns3_copilot/config/forbidden_commands.txt +++ b/gns3server/agent/gns3_copilot/config/forbidden_commands.txt @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/gns3_client/__init__.py b/gns3server/agent/gns3_copilot/gns3_client/__init__.py index a1015ab9e..57b618f61 100644 --- a/gns3server/agent/gns3_copilot/gns3_client/__init__.py +++ b/gns3server/agent/gns3_copilot/gns3_client/__init__.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # @@ -73,7 +73,7 @@ try: except Exception: __version__ = "unknown" -__author__ = "Guobin Yue" +__author__ = "Yue Guobin (岳国宾)" __description__ = "AI-powered network automation assistant for GNS3" __url__ = "https://github.com/yueguobin/gns3-copilot" diff --git a/gns3server/agent/gns3_copilot/gns3_client/connector_factory.py b/gns3server/agent/gns3_copilot/gns3_client/connector_factory.py index 6c127ecbc..fb3a0d25b 100644 --- a/gns3server/agent/gns3_copilot/gns3_client/connector_factory.py +++ b/gns3server/agent/gns3_copilot/gns3_client/connector_factory.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/gns3_client/context_helpers.py b/gns3server/agent/gns3_copilot/gns3_client/context_helpers.py index 33a286a17..424b9e2ae 100644 --- a/gns3server/agent/gns3_copilot/gns3_client/context_helpers.py +++ b/gns3server/agent/gns3_copilot/gns3_client/context_helpers.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/gns3_client/custom_gns3fy.py b/gns3server/agent/gns3_copilot/gns3_client/custom_gns3fy.py index fdf5849bb..3540b4cfb 100644 --- a/gns3server/agent/gns3_copilot/gns3_client/custom_gns3fy.py +++ b/gns3server/agent/gns3_copilot/gns3_client/custom_gns3fy.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/gns3_client/gns3_project_info.py b/gns3server/agent/gns3_copilot/gns3_client/gns3_project_info.py index 0729d64f0..b0bcf09f4 100644 --- a/gns3server/agent/gns3_copilot/gns3_client/gns3_project_info.py +++ b/gns3server/agent/gns3_copilot/gns3_client/gns3_project_info.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/gns3_client/gns3_topology_reader.py b/gns3server/agent/gns3_copilot/gns3_client/gns3_topology_reader.py index 2037929cf..7a858cc3e 100644 --- a/gns3server/agent/gns3_copilot/gns3_client/gns3_topology_reader.py +++ b/gns3server/agent/gns3_copilot/gns3_client/gns3_topology_reader.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/project_agent_manager.py b/gns3server/agent/gns3_copilot/project_agent_manager.py index fd5f6f026..abc6505b2 100644 --- a/gns3server/agent/gns3_copilot/project_agent_manager.py +++ b/gns3server/agent/gns3_copilot/project_agent_manager.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/prompts/__init__.py b/gns3server/agent/gns3_copilot/prompts/__init__.py index f3230cd40..43e810089 100644 --- a/gns3server/agent/gns3_copilot/prompts/__init__.py +++ b/gns3server/agent/gns3_copilot/prompts/__init__.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # @@ -48,7 +48,7 @@ try: except Exception: __version__ = "unknown" -__author__ = "Guobin Yue" +__author__ = "Yue Guobin (岳国宾)" __description__ = "AI-powered network automation assistant for GNS3" __url__ = "https://github.com/yueguobin/gns3-copilot" diff --git a/gns3server/agent/gns3_copilot/prompts/lab_automation_assistant_prompt.py b/gns3server/agent/gns3_copilot/prompts/lab_automation_assistant_prompt.py index f87a696e9..2b8963ad5 100644 --- a/gns3server/agent/gns3_copilot/prompts/lab_automation_assistant_prompt.py +++ b/gns3server/agent/gns3_copilot/prompts/lab_automation_assistant_prompt.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/prompts/prompt_loader.py b/gns3server/agent/gns3_copilot/prompts/prompt_loader.py index 891233a40..b6f5917ab 100644 --- a/gns3server/agent/gns3_copilot/prompts/prompt_loader.py +++ b/gns3server/agent/gns3_copilot/prompts/prompt_loader.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/prompts/teaching_assistant_prompt.py b/gns3server/agent/gns3_copilot/prompts/teaching_assistant_prompt.py index db91b4fa0..e65b95a68 100644 --- a/gns3server/agent/gns3_copilot/prompts/teaching_assistant_prompt.py +++ b/gns3server/agent/gns3_copilot/prompts/teaching_assistant_prompt.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/prompts/title_prompt.py b/gns3server/agent/gns3_copilot/prompts/title_prompt.py index 9192cca1c..480442741 100644 --- a/gns3server/agent/gns3_copilot/prompts/title_prompt.py +++ b/gns3server/agent/gns3_copilot/prompts/title_prompt.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/tools_v2/__init__.py b/gns3server/agent/gns3_copilot/tools_v2/__init__.py index 686e28393..a24d42ab5 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/__init__.py +++ b/gns3server/agent/gns3_copilot/tools_v2/__init__.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # @@ -45,7 +45,7 @@ Main modules: Note: GNS3TopologyTool is now available from gns3_client package -Author: Guobin Yue +Author: Yue Guobin (岳国宾) """ # Import main tool classes @@ -67,7 +67,7 @@ try: except Exception: __version__ = "unknown" -__author__ = "Guobin Yue" +__author__ = "Yue Guobin (岳国宾)" __description__ = "AI-powered network automation assistant for GNS3" __url__ = "https://github.com/yueguobin/gns3-copilot" diff --git a/gns3server/agent/gns3_copilot/tools_v2/config_tools_nornir.py b/gns3server/agent/gns3_copilot/tools_v2/config_tools_nornir.py index fb4b8cebe..4d3ecb2cc 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/config_tools_nornir.py +++ b/gns3server/agent/gns3_copilot/tools_v2/config_tools_nornir.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/tools_v2/display_tools_nornir.py b/gns3server/agent/gns3_copilot/tools_v2/display_tools_nornir.py index 42b11469b..0fb9a703b 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/display_tools_nornir.py +++ b/gns3server/agent/gns3_copilot/tools_v2/display_tools_nornir.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/tools_v2/gns3_create_link.py b/gns3server/agent/gns3_copilot/tools_v2/gns3_create_link.py index e3a328d83..3703213c1 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/gns3_create_link.py +++ b/gns3server/agent/gns3_copilot/tools_v2/gns3_create_link.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/tools_v2/gns3_create_node.py b/gns3server/agent/gns3_copilot/tools_v2/gns3_create_node.py index 1ef1d969c..dd7586f15 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/gns3_create_node.py +++ b/gns3server/agent/gns3_copilot/tools_v2/gns3_create_node.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/tools_v2/gns3_get_node_temp.py b/gns3server/agent/gns3_copilot/tools_v2/gns3_get_node_temp.py index ab106edd5..ff0306416 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/gns3_get_node_temp.py +++ b/gns3server/agent/gns3_copilot/tools_v2/gns3_get_node_temp.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/tools_v2/gns3_start_node.py b/gns3server/agent/gns3_copilot/tools_v2/gns3_start_node.py index e6aa21001..e6a20210c 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/gns3_start_node.py +++ b/gns3server/agent/gns3_copilot/tools_v2/gns3_start_node.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/tools_v2/gns3_update_node_name.py b/gns3server/agent/gns3_copilot/tools_v2/gns3_update_node_name.py index 586bbf43b..bf8253320 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/gns3_update_node_name.py +++ b/gns3server/agent/gns3_copilot/tools_v2/gns3_update_node_name.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/tools_v2/vpcs_tools_telnetlib3.py b/gns3server/agent/gns3_copilot/tools_v2/vpcs_tools_telnetlib3.py index 0b15a59bc..d81a10621 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/vpcs_tools_telnetlib3.py +++ b/gns3server/agent/gns3_copilot/tools_v2/vpcs_tools_telnetlib3.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/utils/__init__.py b/gns3server/agent/gns3_copilot/utils/__init__.py index 9cc0371eb..983ce3b03 100644 --- a/gns3server/agent/gns3_copilot/utils/__init__.py +++ b/gns3server/agent/gns3_copilot/utils/__init__.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # @@ -33,7 +33,7 @@ Main modules: - get_gns3_device_port: Device port information retrieval from GNS3 topology - parse_tool_content: Tool execution result parsing and formatting utilities -Author: Guobin Yue +Author: Yue Guobin (岳国宾) """ # Import main utility functions @@ -50,7 +50,7 @@ try: except Exception: __version__ = "unknown" -__author__ = "Guobin Yue" +__author__ = "Yue Guobin (岳国宾)" __description__ = "AI-powered network automation assistant for GNS3" __url__ = "https://github.com/yueguobin/gns3-copilot" diff --git a/gns3server/agent/gns3_copilot/utils/command_filter.py b/gns3server/agent/gns3_copilot/utils/command_filter.py index 92dce1997..44d8d53e0 100644 --- a/gns3server/agent/gns3_copilot/utils/command_filter.py +++ b/gns3server/agent/gns3_copilot/utils/command_filter.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/utils/get_gns3_device_port.py b/gns3server/agent/gns3_copilot/utils/get_gns3_device_port.py index eda3cd19e..951f7ba7f 100644 --- a/gns3server/agent/gns3_copilot/utils/get_gns3_device_port.py +++ b/gns3server/agent/gns3_copilot/utils/get_gns3_device_port.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/utils/gns3_drawing_utils.py b/gns3server/agent/gns3_copilot/utils/gns3_drawing_utils.py index c676a1f06..4fa48ee7d 100644 --- a/gns3server/agent/gns3_copilot/utils/gns3_drawing_utils.py +++ b/gns3server/agent/gns3_copilot/utils/gns3_drawing_utils.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/utils/llm_config_helper.py b/gns3server/agent/gns3_copilot/utils/llm_config_helper.py index d0f43be5f..4aab3a72c 100644 --- a/gns3server/agent/gns3_copilot/utils/llm_config_helper.py +++ b/gns3server/agent/gns3_copilot/utils/llm_config_helper.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # diff --git a/gns3server/agent/gns3_copilot/utils/message_converters.py b/gns3server/agent/gns3_copilot/utils/message_converters.py index dc599e893..d6d9dc2e7 100644 --- a/gns3server/agent/gns3_copilot/utils/message_converters.py +++ b/gns3server/agent/gns3_copilot/utils/message_converters.py @@ -2,8 +2,8 @@ # # GNS3-Copilot - AI-powered Network Lab Assistant for GNS3 # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # This file is part of GNS3-Copilot project. # diff --git a/gns3server/agent/gns3_copilot/utils/parse_tool_content.py b/gns3server/agent/gns3_copilot/utils/parse_tool_content.py index 6cc32b65d..46ee4b7fe 100644 --- a/gns3server/agent/gns3_copilot/utils/parse_tool_content.py +++ b/gns3server/agent/gns3_copilot/utils/parse_tool_content.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot # @@ -60,7 +60,7 @@ Standard Tool Response Format: "error": str # Error message (if failed) } -Author: Guobin Yue +Author: Yue Guobin (岳国宾) """ import ast diff --git a/gns3server/agent/gns3_copilot/utils/tool_call_stream.py b/gns3server/agent/gns3_copilot/utils/tool_call_stream.py index c598adb84..4fd5b51a1 100644 --- a/gns3server/agent/gns3_copilot/utils/tool_call_stream.py +++ b/gns3server/agent/gns3_copilot/utils/tool_call_stream.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with GNS3-Copilot. If not, see . # -# Copyright (C) 2025 Guobin Yue -# Author: Guobin Yue +# Copyright (C) 2025 Yue Guobin (岳国宾) +# Author: Yue Guobin (岳国宾) # # Project Home: https://github.com/yueguobin/gns3-copilot #