Files
troupe-standup/wizard-work/spark/profile-inspector.py
T

146 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""
Hermes Profile Inspector - Inspects a Hermes profile and outputs structured JSON.
Usage: python3 profile-inspector.py <profile_name>
Outputs JSON with: model, provider, skill_count, cron_count, verification status.
"""
import json
import os
import sys
from pathlib import Path
from typing import Any
def discover_model_provider(profile_name: str) -> tuple[str, str]:
"""Discover model and provider from profile config.yaml"""
config_path = Path(f"/root/.hermes/profiles/{profile_name}/config.yaml")
if not config_path.exists():
return "unknown", "unknown"
try:
import yaml
with open(config_path) as f:
cfg = yaml.safe_load(f)
model_config = cfg.get("model", {})
if isinstance(model_config, dict):
model = model_config.get("default", "unknown")
provider = model_config.get("provider", "unknown")
else:
model = str(model_config)
provider = "unknown"
return str(model), str(provider)
except Exception:
return "unknown", "unknown"
def discover_skills(profile_path: Path) -> list[str]:
"""Discover skill names from profile skills directory"""
skills_dir = profile_path / "skills"
if not skills_dir.exists():
return []
skills = []
for skill_dir in skills_dir.rglob("*"):
if skill_dir.is_dir():
skill_info = skill_dir / "SKILL.md"
if skill_info.exists():
skills.append(skill_dir.name)
return sorted(set(skills))
def discover_crons(profile_path: Path) -> list[str]:
"""Discover cron job names from profile cron directory"""
cron_dir = profile_path / "cron"
if not cron_dir.exists():
return []
crons = []
for item in cron_dir.iterdir():
if item.is_file() and item.suffix == ".py":
crons.append(item.stem)
return sorted(crons)
def _find_in_dict(data, target, depth=0, max_depth=10):
"""Recursively search for target key in nested dict/list structure"""
if depth > max_depth:
return False
if isinstance(data, dict):
if target in data:
return True
for v in data.values():
if _find_in_dict(v, target, depth + 1, max_depth):
return True
elif isinstance(data, list):
for item in data:
if _find_in_dict(item, target, depth + 1, max_depth):
return True
return False
def verify_model_chain(profile_name: str, model: str, provider: str) -> dict[str, Any]:
"""Verify the model exists in provider's model cache"""
models_cache_path = Path(f"/root/.hermes/profiles/{profile_name}/models_dev_cache.json")
if not models_cache_path.exists():
return {"cache_found": False}
try:
with open(models_cache_path) as f:
cache = json.load(f)
# Check if model is in cache (recursively search nested structure)
model_found = _find_in_dict(cache, model)
return {
"cache_found": True,
"model_in_cache": model_found,
"model": model,
"provider": provider
}
except Exception as e:
return {"cache_found": True, "error": str(e)}
def build_profile_report(profile_name: str) -> dict[str, Any]:
"""Build structured report for a Hermes profile"""
profile_path = Path(f"/root/.hermes/profiles/{profile_name}")
if not profile_path.exists():
return {"error": f"Profile {profile_name} not found", "exists": False}
model, provider = discover_model_provider(profile_name)
skills = discover_skills(profile_path)
crons = discover_crons(profile_path)
# Count files in profile
stat = profile_path.stat()
return {
"exists": True,
"profile": profile_name,
"model": model,
"provider": provider,
"skills": {
"count": len(skills),
"names": skills
},
"crons": {
"count": len(crons),
"names": crons
},
"profile_path": str(profile_path),
"memory_kb": stat.st_size // 1024,
"verified": True
}
if __name__ == "__main__":
if len(sys.argv) < 2:
print(json.dumps({"error": "Usage: profile-inspector.py <profile_name>"}))
sys.exit(1)
profile = sys.argv[1]
report = build_profile_report(profile)
if report.get("exists"):
model = report.get("model", "unknown")
provider = report.get("provider", "unknown")
report["model_verification"] = verify_model_chain(profile, model, provider)
print(json.dumps(report, indent=2))