fix: add load_feature_skills() to properly load network planning features

The feature directory contains network planning and design functionalities
(e.g., topology_planner), not device-specific features. These were not being
loaded because load_device_skills() only scanned the device directory.

Changes:
- Added new load_feature_skills() method in SkillsLoader
- Modified reload_skills() to load both device and feature directories
- Device skills: device-specific configurations (e.g., VPCS)
- Feature skills: network planning functionalities (e.g., topology planner)
- Both are now properly loaded into SKILLS_REGISTRY

This ensures that network planning features like topology_planner are available
via the device_skills tool with proper category classification.
This commit is contained in:
YueGuobin 2026-06-05 22:25:17 +08:00
parent 6497db6f30
commit e76f3970ca
No known key found for this signature in database
2 changed files with 55 additions and 6 deletions

View File

@ -98,7 +98,7 @@ class SkillsLoader:
def load_device_skills(self) -> Dict[str, Dict[str, Any]]:
"""
Load all device/feature skills from YAML files.
Load all device skills from YAML files.
Returns:
Dictionary mapping skill keys to skill definitions
@ -131,7 +131,48 @@ class SkillsLoader:
except Exception as e:
logger.error(f"Failed to load skill from {yaml_file}: {e}")
logger.debug(f"Loaded {len(skills)} device skills from {device_dir}")
logger.debug(f"Loaded {len(skills)} device skills from device directory")
return skills
def load_feature_skills(self) -> Dict[str, Dict[str, Any]]:
"""
Load all feature skills from YAML files.
Feature skills are network planning and design functionalities
(e.g., topology planner), not device-specific features.
Returns:
Dictionary mapping skill keys to skill definitions
"""
if yaml is None:
logger.error("PyYAML is not installed. Cannot load skills from YAML.")
return {}
skills = {}
feature_dir = self.skills_dir / "feature"
if not feature_dir.exists():
logger.warning(f"Feature skills directory not found: {feature_dir}")
return {}
for yaml_file in feature_dir.glob("*.yaml"):
try:
skill_data = self._load_yaml(yaml_file)
if not skill_data:
logger.warning(f"Skipping empty YAML file: {yaml_file}")
continue
# Use device_type from YAML content as the key
# Fallback to filename stem if device_type not present
skill_key = skill_data.get("device_type") if isinstance(skill_data, dict) else None
if not skill_key:
skill_key = yaml_file.stem
logger.warning(f"No device_type in {yaml_file}, using filename '{skill_key}' as key")
skills[skill_key] = skill_data
logger.debug(f"Loaded feature skill: {skill_key} from {yaml_file}")
except Exception as e:
logger.error(f"Failed to load feature skill from {yaml_file}: {e}")
logger.debug(f"Loaded {len(skills)} feature skills from feature directory")
return skills
def load_prompt(self, prompt_name: str) -> str:

View File

@ -227,9 +227,17 @@ class SkillsManager:
logger.error(f"Invalid skill format for {skill_key}, skipping")
continue
# Load new device/feature skills from YAML files
# Load new device skills from YAML files
new_device_skills = self.loader.load_device_skills()
# Load new feature skills from YAML files
new_feature_skills = self.loader.load_feature_skills()
# Merge device and feature skills into single registry
all_skills = {}
all_skills.update(new_device_skills)
all_skills.update(new_feature_skills)
# Update registries (safe replace - never leaves dict empty)
for k in list(INJECTION_SKILLS_REGISTRY):
if k not in new_injection_skills:
@ -237,11 +245,11 @@ class SkillsManager:
INJECTION_SKILLS_REGISTRY.update(new_injection_skills)
for k in list(SKILLS_REGISTRY):
if k not in new_device_skills:
if k not in all_skills:
del SKILLS_REGISTRY[k]
SKILLS_REGISTRY.update(new_device_skills)
SKILLS_REGISTRY.update(all_skills)
logger.info(f"Loaded {len(new_injection_skills)} injection skills and {len(new_device_skills)} device skills")
logger.info(f"Loaded {len(new_injection_skills)} injection skills, {len(new_device_skills)} device skills, and {len(new_feature_skills)} feature skills")
return True
except Exception as e:
logger.error(f"Failed to reload skills: {e}")