diff --git a/gns3server/agent/__init__.py b/gns3server/agent/__init__.py index 2fc6bc515..1861ed37e 100644 --- a/gns3server/agent/__init__.py +++ b/gns3server/agent/__init__.py @@ -37,26 +37,13 @@ try: 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 + # Start skills repository initialization in background. + # Clones/pulls GNS3-Skills during server startup. + # Git network timeouts are configured in SkillsManager (_GIT_TIMEOUT_ENV). + # The daemon thread auto-terminates when the process exits. + 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() + threading.Thread(target=_ensure_skills_manager, daemon=True).start() except ImportError as e: # AI dependencies not installed, disable AI Copilot feature diff --git a/gns3server/agent/gns3_copilot/skills/manager.py b/gns3server/agent/gns3_copilot/skills/manager.py index 870c90960..c5ca14c47 100644 --- a/gns3server/agent/gns3_copilot/skills/manager.py +++ b/gns3server/agent/gns3_copilot/skills/manager.py @@ -51,7 +51,7 @@ logger = logging.getLogger(__name__) _GIT_TIMEOUT_ENV = { 'GIT_HTTP_TIMEOUT': '10', # Connection timeout (default: 120s) 'GIT_HTTP_LOW_SPEED_TIME': '5', # Slow speed threshold window - 'GIT_HTTP_LOW_SPEED_LIMIT': '1000', # < 1 KB/s = slow → abort + 'GIT_HTTP_LOW_SPEED_LIMIT': '10240', # < 10 KB/s = slow → abort } diff --git a/gns3server/agent/gns3_copilot/skills/registry.py b/gns3server/agent/gns3_copilot/skills/registry.py index e13b258f8..eed12608b 100644 --- a/gns3server/agent/gns3_copilot/skills/registry.py +++ b/gns3server/agent/gns3_copilot/skills/registry.py @@ -57,7 +57,6 @@ INJECTION_SKILLS_REGISTRY: dict[str, dict[str, Any]] = {} # Global skills manager instance for hot reload _skills_manager = None _init_in_progress = False -_init_complete = False def set_skills_manager(manager): @@ -75,16 +74,21 @@ def set_skills_manager(manager): def _ensure_skills_manager(): """ - Initialize the SkillsManager (runs once, idempotent). + Initialize the SkillsManager (idempotent, retryable on failure). Reads config, creates SkillsManager, clones/pulls repo, and loads skills/prompts into memory. Safe to call from background threads - uses _init_in_progress to prevent concurrent initialization. - """ - global _skills_manager, _init_in_progress, _init_complete - if _skills_manager is not None or _init_complete: + On failure, resets _init_in_progress so future calls + (e.g., /reload/skills API) can retry. On success, the + manager is stored in _skills_manager and subsequent + calls return immediately. + """ + global _skills_manager, _init_in_progress + + if _skills_manager is not None: return if _init_in_progress: @@ -130,7 +134,7 @@ def _ensure_skills_manager(): except Exception as e: logger.error(f"Error initializing skills manager: {e}", exc_info=True) finally: - _init_complete = True + _init_in_progress = False def get_skills_manager():