feat: add fault injection system and external skills repository

## Summary

Add a complete fault injection system for GNS3 Copilot, migrate all
skills from local Python files to an external Git repository with
hot reload support, and restructure Copilot API under /copilot/.

## Key Changes

### Fault Injection
- New troubleshooting_injection mode with InjectionSkillsTool
- 368 fault scenarios across 39 protocol categories
- Context-based filtering (LLM must pass topology protocols)

### External Skills Repository
- SkillsManager: Git clone/pull, version tracking, smart updates
- SkillsLoader: YAML skills + Markdown prompts from external repo
- Hot reload via POST /copilot/reload/skills
- Configurable via gns3_server.conf

### Architecture
- API unified under /copilot/ prefix
- SkillsManager moved from Controller to agent module
- Lazy initialization with startup background preload
- Per-command Git timeout, smart update checks
- Forbidden commands hot-reloadable from external repo
- 32 INFO logs downgraded to DEBUG
This commit is contained in:
YueGuobin committed 2026-05-11 01:24:55 +08:00
1 parent 534bb5eded
commit e68cc17ed5
42 files changed
+2182 -1260

No files matched your search

+23
View File
@@ -26,6 +26,7 @@ Installation:
"""
import logging
import threading
# Feature flag: AI Copilot is available
AI_COPILOT_AVAILABLE = False
@@ -35,6 +36,28 @@ try:
from .gns3_copilot.project_agent_manager import get_project_agent_manager
from .gns3_copilot.project_agent_manager import ProjectAgentManager
AI_COPILOT_AVAILABLE = True
# Start skills repository initialization in background with 5s timeout.
# This clones/pulls GNS3-Skills during server startup.
# If GitHub is unreachable (common in some regions), the timeout
# ensures the server starts without delay, using fallback defaults.
def _init_skills_background():
"""Initialize skills repo - called from background thread."""
from gns3server.agent.gns3_copilot.skills.registry import _ensure_skills_manager
t = threading.Thread(target=_ensure_skills_manager, daemon=True)
t.start()
t.join(5)
if t.is_alive():
log = logging.getLogger(__name__)
log.warning(
"Skills repository initialization timed out (5s). "
"Will use fallback defaults. "
"The background thread will complete when network is available."
)
threading.Thread(target=_init_skills_background, daemon=True).start()
except ImportError as e:
# AI dependencies not installed, disable AI Copilot feature
logging.warning(