Spaces:
Running
Running
Deploy Aureon OS (deploy/selfhost stack: nginx edge + fusion API x2 + console + HNC organ + redis + postgres; paper mode) (part 3)
1ccf652 verified Download aureon/code_architect/skill_library.py from GaryLeckey/aureon-os: direct link, hf CLI and curl.
- Browser
- Download file 14.2 kB
-
https://huggingface.co/spaces/GaryLeckey/aureon-os/resolve/main/aureon/code_architect/skill_library.py
- Command line
-
hf download hf://spaces/GaryLeckey/aureon-os/aureon/code_architect/skill_library.py
-
curl -L -o skill_library.py https://huggingface.co/spaces/GaryLeckey/aureon-os/resolve/main/aureon/code_architect/skill_library.py
14.2 kB
| """ | |
| SkillLibrary β the persistent registry of learned skills | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| Persists skills to JSON under state/skills/. Supports: | |
| - by-name lookup (fast path) | |
| - by-level filter | |
| - by-category filter | |
| - by-tag filter | |
| - dependency resolution (given a skill, return the full tree of deps) | |
| - execution-stat updates (success/failure/duration) | |
| - atomic bulk save/load | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import logging | |
| import os | |
| import threading | |
| import time | |
| from pathlib import Path | |
| from typing import Any, Dict, List, Optional | |
| from aureon.code_architect.skill import Skill, SkillLevel, SkillStatus | |
| logger = logging.getLogger("aureon.code_architect.library") | |
| class SkillLibrary: | |
| """Thread-safe persistent skill registry.""" | |
| DEFAULT_STORAGE_DIR = Path("state/skills") | |
| LIBRARY_FILE = "skill_library.json" | |
| def __init__(self, storage_dir: Optional[Path] = None): | |
| self.storage_dir = Path(storage_dir or self.DEFAULT_STORAGE_DIR) | |
| self.storage_dir.mkdir(parents=True, exist_ok=True) | |
| self.library_path = self.storage_dir / self.LIBRARY_FILE | |
| self._skills: Dict[str, Skill] = {} # name β Skill | |
| self._lock = threading.RLock() | |
| self._load() | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Load / save | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _load(self) -> None: | |
| if not self.library_path.exists(): | |
| return | |
| try: | |
| with open(self.library_path, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| if isinstance(data, dict): | |
| skills = data.get("skills", []) | |
| elif isinstance(data, list): | |
| skills = data | |
| else: | |
| skills = [] | |
| with self._lock: | |
| for skill_data in skills: | |
| try: | |
| skill = Skill.from_dict(skill_data) | |
| self._skills[skill.name] = skill | |
| except Exception as e: | |
| logger.warning("Failed to load skill %s: %s", skill_data.get("name"), e) | |
| logger.info("Loaded %d skills from %s", len(self._skills), self.library_path) | |
| except Exception as e: | |
| logger.warning("Library load failed: %s", e) | |
| def save(self) -> None: | |
| with self._lock: | |
| data = { | |
| "version": 1, | |
| "saved_at": time.time(), | |
| "count": len(self._skills), | |
| "skills": [s.to_dict() for s in self._skills.values()], | |
| } | |
| try: | |
| tmp = self.library_path.with_suffix(".json.tmp") | |
| with open(tmp, "w", encoding="utf-8") as f: | |
| json.dump(data, f, indent=2) | |
| os.replace(tmp, self.library_path) | |
| except Exception as e: | |
| logger.warning("Library save failed: %s", e) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CRUD | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def add(self, skill: Skill, persist: bool = True) -> Skill: | |
| """Add or overwrite a skill.""" | |
| if not skill.name: | |
| raise ValueError("skill.name is required") | |
| with self._lock: | |
| self._skills[skill.name] = skill | |
| if persist: | |
| self.save() | |
| return skill | |
| def get(self, name: str) -> Optional[Skill]: | |
| with self._lock: | |
| return self._skills.get(name) | |
| def remove(self, name: str, persist: bool = True) -> bool: | |
| with self._lock: | |
| removed = self._skills.pop(name, None) is not None | |
| if removed and persist: | |
| self.save() | |
| return removed | |
| def contains(self, name: str) -> bool: | |
| with self._lock: | |
| return name in self._skills | |
| def __contains__(self, name: str) -> bool: | |
| return self.contains(name) | |
| def __len__(self) -> int: | |
| with self._lock: | |
| return len(self._skills) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Filters | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def all(self) -> List[Skill]: | |
| with self._lock: | |
| return list(self._skills.values()) | |
| def by_level(self, level: SkillLevel) -> List[Skill]: | |
| with self._lock: | |
| return [s for s in self._skills.values() if s.level == level] | |
| def by_category(self, category: str) -> List[Skill]: | |
| with self._lock: | |
| return [s for s in self._skills.values() if s.category == category] | |
| def by_tag(self, tag: str) -> List[Skill]: | |
| with self._lock: | |
| return [s for s in self._skills.values() if tag in s.tags] | |
| def by_status(self, status: SkillStatus) -> List[Skill]: | |
| with self._lock: | |
| return [s for s in self._skills.values() if s.status == status] | |
| def search(self, substring: str) -> List[Skill]: | |
| substring = substring.lower() | |
| with self._lock: | |
| return [ | |
| s for s in self._skills.values() | |
| if substring in s.name.lower() or substring in s.description.lower() | |
| ] | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Dependency resolution | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def resolve_dependencies(self, name: str) -> List[Skill]: | |
| """ | |
| Return the full transitive dependency closure of a skill | |
| topologically sorted (dependencies before the skill itself). | |
| Iterative implementation so very deep chains (thousands of levels) | |
| don't hit Python's recursion limit. Handles missing deps and | |
| cycles gracefully (missing deps are skipped, cycles are broken). | |
| """ | |
| root = self.get(name) | |
| if not root: | |
| return [] | |
| # Iterative DFS with post-order emit for topological sort. | |
| # Stack entries: (skill, child_index) | |
| ordered: List[Skill] = [] | |
| seen_in_order: set = set() # names already appended to `ordered` | |
| on_stack: set = set() # names currently on the DFS stack (cycle guard) | |
| stack: List[Any] = [[root, 0]] | |
| on_stack.add(root.name) | |
| while stack: | |
| top = stack[-1] | |
| skill, idx = top[0], top[1] | |
| if idx >= len(skill.dependencies): | |
| # All children processed β emit this skill | |
| stack.pop() | |
| on_stack.discard(skill.name) | |
| if skill.name not in seen_in_order: | |
| ordered.append(skill) | |
| seen_in_order.add(skill.name) | |
| continue | |
| # Advance the iterator before descending | |
| top[1] = idx + 1 | |
| dep_name = skill.dependencies[idx] | |
| if dep_name in seen_in_order: | |
| continue # already emitted | |
| if dep_name in on_stack: | |
| continue # cycle β skip the back edge | |
| dep = self.get(dep_name) | |
| if dep is None: | |
| continue # missing dep β skip | |
| stack.append([dep, 0]) | |
| on_stack.add(dep_name) | |
| return ordered | |
| def has_cycles(self) -> bool: | |
| """Check if the skill graph contains cycles (iterative DFS).""" | |
| with self._lock: | |
| visited: set = set() | |
| for start_name in list(self._skills.keys()): | |
| if start_name in visited: | |
| continue | |
| if self._detect_cycle_iterative(start_name, visited): | |
| return True | |
| return False | |
| def _detect_cycle_iterative(self, start: str, global_visited: set) -> bool: | |
| """Iterative DFS cycle detector for one connected component.""" | |
| on_stack: set = set() | |
| stack: List[Any] = [[start, 0]] | |
| on_stack.add(start) | |
| while stack: | |
| top = stack[-1] | |
| name, idx = top[0], top[1] | |
| skill = self._skills.get(name) | |
| if skill is None or idx >= len(skill.dependencies): | |
| stack.pop() | |
| on_stack.discard(name) | |
| global_visited.add(name) | |
| continue | |
| top[1] = idx + 1 | |
| dep_name = skill.dependencies[idx] | |
| if dep_name in on_stack: | |
| return True # back edge β cycle | |
| if dep_name in global_visited: | |
| continue | |
| if dep_name in self._skills: | |
| stack.append([dep_name, 0]) | |
| on_stack.add(dep_name) | |
| return False | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Execution stat updates | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def record_execution( | |
| self, | |
| name: str, | |
| success: bool, | |
| duration_s: float, | |
| error: Optional[str] = None, | |
| persist: bool = False, | |
| ) -> None: | |
| with self._lock: | |
| skill = self._skills.get(name) | |
| if not skill: | |
| return | |
| skill.execution_count += 1 | |
| if success: | |
| skill.success_count += 1 | |
| else: | |
| skill.failure_count += 1 | |
| skill.last_error = error | |
| skill.last_execution_at = time.time() | |
| # Online mean | |
| if skill.execution_count == 1: | |
| skill.mean_duration_s = duration_s | |
| else: | |
| n = skill.execution_count | |
| skill.mean_duration_s = skill.mean_duration_s + (duration_s - skill.mean_duration_s) / n | |
| if persist: | |
| self.save() | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Stats | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def get_stats(self) -> Dict[str, Any]: | |
| with self._lock: | |
| by_level: Dict[str, int] = {} | |
| by_status: Dict[str, int] = {} | |
| by_category: Dict[str, int] = {} | |
| total_exec = 0 | |
| total_success = 0 | |
| for s in self._skills.values(): | |
| by_level[s.level.name] = by_level.get(s.level.name, 0) + 1 | |
| by_status[s.status.value] = by_status.get(s.status.value, 0) + 1 | |
| by_category[s.category] = by_category.get(s.category, 0) + 1 | |
| total_exec += s.execution_count | |
| total_success += s.success_count | |
| return { | |
| "total_skills": len(self._skills), | |
| "by_level": by_level, | |
| "by_status": by_status, | |
| "by_category": by_category, | |
| "total_executions": total_exec, | |
| "total_successes": total_success, | |
| "overall_success_rate": ( | |
| total_success / total_exec if total_exec > 0 else 0.0 | |
| ), | |
| "has_cycles": self.has_cycles(), | |
| "storage_path": str(self.library_path), | |
| } | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Singleton | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| _library_instance: Optional[SkillLibrary] = None | |
| _library_lock = threading.Lock() | |
| def get_skill_library(storage_dir: Optional[Path] = None) -> SkillLibrary: | |
| """Get or create the singleton SkillLibrary.""" | |
| global _library_instance | |
| with _library_lock: | |
| if _library_instance is None: | |
| _library_instance = SkillLibrary(storage_dir=storage_dir) | |
| return _library_instance | |