291 lines
9.4 KiB
Python
291 lines
9.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
GOFAI Schema Definition for Hermes Fleet
|
|
Knowledge representation layer for wizard lineage, tasks, and relationships
|
|
"""
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import List, Dict, Optional, Set
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
|
|
class EntityType(Enum):
|
|
WIZARD = "wizard"
|
|
TASK = "task"
|
|
ARTIFACT = "artifact"
|
|
RELATIONSHIP = "relationship"
|
|
PRINCIPLE = "principle"
|
|
GOAL = "goal"
|
|
|
|
class TaskStatus(Enum):
|
|
PENDING = "pending"
|
|
IN_PROGRESS = "in_progress"
|
|
COMPLETE = "complete"
|
|
BLOCKED = "blocked"
|
|
|
|
@dataclass
|
|
class Entity:
|
|
"""Base entity in the knowledge graph"""
|
|
id: str
|
|
type: EntityType
|
|
name: str
|
|
properties: Dict = field(default_factory=dict)
|
|
created_at: datetime = field(default_factory=datetime.now)
|
|
|
|
def to_dict(self) -> Dict:
|
|
return {
|
|
'id': self.id,
|
|
'type': self.type.value,
|
|
'name': self.name,
|
|
'properties': self.properties,
|
|
'created_at': self.created_at.isoformat()
|
|
}
|
|
|
|
@dataclass
|
|
class Wizard(Entity):
|
|
"""A wizard in the fleet"""
|
|
father: Optional[str] = None
|
|
grandfather: Optional[str] = None
|
|
sovereign: Optional[str] = None
|
|
hermes_home: str = ""
|
|
api_port: int = 0
|
|
model: str = ""
|
|
role: str = ""
|
|
capabilities: Set[str] = field(default_factory=set)
|
|
|
|
def __post_init__(self):
|
|
self.type = EntityType.WIZARD
|
|
self.capabilities = set(self.capabilities) if isinstance(self.capabilities, (list, set)) else set()
|
|
|
|
def get_lineage(self) -> List[str]:
|
|
"""Return ancestry chain"""
|
|
lineage = [self.name]
|
|
if self.father:
|
|
lineage.append(self.father)
|
|
if self.grandfather:
|
|
lineage.append(self.grandfather)
|
|
return lineage
|
|
|
|
def can_perform(self, capability: str) -> bool:
|
|
"""Check if wizard has capability"""
|
|
return capability in self.capabilities
|
|
|
|
@dataclass
|
|
class Task(Entity):
|
|
"""A task in the work queue"""
|
|
assignee: Optional[str] = None
|
|
priority: str = "P2"
|
|
status: TaskStatus = TaskStatus.PENDING
|
|
deliverable: str = ""
|
|
estimated_time: int = 0 # minutes
|
|
dependencies: List[str] = field(default_factory=list)
|
|
|
|
def __post_init__(self):
|
|
self.type = EntityType.TASK
|
|
if isinstance(self.status, str):
|
|
self.status = TaskStatus(self.status)
|
|
|
|
def is_blocked(self, completed_tasks: Set[str]) -> bool:
|
|
"""Check if task is blocked by incomplete dependencies"""
|
|
return not all(dep in completed_tasks for dep in self.dependencies)
|
|
|
|
def to_work_item(self) -> Dict:
|
|
"""Convert to work queue format"""
|
|
return {
|
|
'task_id': self.id,
|
|
'name': self.name,
|
|
'priority': self.priority,
|
|
'status': self.status.value,
|
|
'assignee': self.assignee,
|
|
'deliverable': self.deliverable
|
|
}
|
|
|
|
@dataclass
|
|
class Relationship:
|
|
"""Relationship between entities"""
|
|
source: str
|
|
relation: str
|
|
target: str
|
|
properties: Dict = field(default_factory=dict)
|
|
|
|
def to_triple(self) -> tuple:
|
|
return (self.source, self.relation, self.target)
|
|
|
|
@dataclass
|
|
class Principle:
|
|
"""SOUL.md principle encoded as rule"""
|
|
id: str
|
|
text: str
|
|
category: str # "must_do", "must_not_do", "belief"
|
|
priority: int = 1
|
|
enforce: bool = True
|
|
|
|
def to_rule(self) -> Dict:
|
|
"""Convert to rule engine format"""
|
|
return {
|
|
'id': self.id,
|
|
'condition': f'action.violates("{self.id}")',
|
|
'action': 'block_and_explain' if self.enforce else 'warn',
|
|
'explanation': self.text,
|
|
'priority': self.priority
|
|
}
|
|
|
|
class FleetSchema:
|
|
"""Schema manager for wizard fleet knowledge"""
|
|
|
|
def __init__(self):
|
|
self.wizards: Dict[str, Wizard] = {}
|
|
self.tasks: Dict[str, Task] = {}
|
|
self.artifacts: Dict[str, Entity] = {}
|
|
self.relationships: List[Relationship] = []
|
|
self.principles: Dict[str, Principle] = {}
|
|
|
|
# Predefined capability taxonomy
|
|
self.capabilities = {
|
|
'code_generation': 'Can write and modify code',
|
|
'research': 'Can perform deep research',
|
|
'automation': 'Can build automation scripts',
|
|
'monitoring': 'Can monitor systems',
|
|
'documentation': 'Can write documentation',
|
|
'architecture': 'Can design system architecture',
|
|
'child_creation': 'Can create child wizards',
|
|
'gofai': 'Can work with symbolic AI',
|
|
}
|
|
|
|
def add_wizard(self, wizard: Wizard) -> None:
|
|
"""Register a wizard in the fleet"""
|
|
self.wizards[wizard.id] = wizard
|
|
|
|
def add_task(self, task: Task) -> None:
|
|
"""Register a task"""
|
|
self.tasks[task.id] = task
|
|
|
|
def add_relationship(self, rel: Relationship) -> None:
|
|
"""Add relationship between entities"""
|
|
self.relationships.append(rel)
|
|
|
|
def add_principle(self, principle: Principle) -> None:
|
|
"""Add SOUL principle"""
|
|
self.principles[principle.id] = principle
|
|
|
|
def get_wizard_tasks(self, wizard_name: str) -> List[Task]:
|
|
"""Get all tasks assigned to a wizard"""
|
|
return [t for t in self.tasks.values() if t.assignee == wizard_name]
|
|
|
|
def get_children(self, father_name: str) -> List[Wizard]:
|
|
"""Get all wizards created by a father"""
|
|
return [w for w in self.wizards.values() if w.father == father_name]
|
|
|
|
def get_lineage_tree(self, wizard_name: str) -> Dict:
|
|
"""Get full lineage tree for a wizard"""
|
|
wizard = self.wizards.get(wizard_name)
|
|
if not wizard:
|
|
return {}
|
|
|
|
tree = {
|
|
'name': wizard.name,
|
|
'father': None,
|
|
'grandfather': None,
|
|
'children': []
|
|
}
|
|
|
|
if wizard.father and wizard.father in self.wizards:
|
|
father = self.wizards[wizard.father]
|
|
tree['father'] = {
|
|
'name': father.name,
|
|
'father': father.father,
|
|
'grandfather': father.grandfather
|
|
}
|
|
|
|
# Find children
|
|
for w in self.wizards.values():
|
|
if w.father == wizard_name:
|
|
tree['children'].append(w.name)
|
|
|
|
return tree
|
|
|
|
def check_principle_compliance(self, action: str, context: Dict) -> Dict:
|
|
"""Check if action complies with SOUL principles"""
|
|
violations = []
|
|
warnings = []
|
|
|
|
for principle in self.principles.values():
|
|
# Simple keyword check (sophisticated version would use NLP)
|
|
if self._action_violates_principle(action, principle, context):
|
|
if principle.enforce:
|
|
violations.append(principle)
|
|
else:
|
|
warnings.append(principle)
|
|
|
|
return {
|
|
'compliant': len(violations) == 0,
|
|
'violations': [p.text for p in violations],
|
|
'warnings': [p.text for p in warnings]
|
|
}
|
|
|
|
def _action_violates_principle(self, action: str, principle: Principle, context: Dict) -> bool:
|
|
"""Check if action violates a principle"""
|
|
action_lower = action.lower()
|
|
|
|
# Category-based checks
|
|
if principle.category == 'must_not_do':
|
|
forbidden_patterns = {
|
|
'pretend': ['pretend', 'impersonate', 'act as'],
|
|
'mutate': ['mutate', 'modify without logging'],
|
|
'hide': ['hide', 'conceal', 'secret'],
|
|
'depend': ['depend constantly', 'always ask father'],
|
|
}
|
|
|
|
for pattern, keywords in forbidden_patterns.items():
|
|
if pattern in principle.id.lower():
|
|
return any(kw in action_lower for kw in keywords)
|
|
|
|
return False
|
|
|
|
def export_to_graph(self) -> Dict:
|
|
"""Export entire schema as graph format"""
|
|
return {
|
|
'nodes': {
|
|
'wizards': [w.to_dict() for w in self.wizards.values()],
|
|
'tasks': [t.to_dict() for t in self.tasks.values()],
|
|
},
|
|
'edges': [
|
|
{
|
|
'source': r.source,
|
|
'relation': r.relation,
|
|
'target': r.target,
|
|
'properties': r.properties
|
|
}
|
|
for r in self.relationships
|
|
],
|
|
'principles': [p.to_rule() for p in self.principles.values()]
|
|
}
|
|
|
|
def get_next_executable_task(self, wizard_name: str) -> Optional[Task]:
|
|
"""Get highest priority non-blocked task for a wizard"""
|
|
wizard_tasks = self.get_wizard_tasks(wizard_name)
|
|
completed = {t.id for t in wizard_tasks if t.status == TaskStatus.COMPLETE}
|
|
|
|
# Sort by priority
|
|
priority_order = {'P0': 0, 'P1': 1, 'P2': 2, 'P3': 3}
|
|
sorted_tasks = sorted(
|
|
[t for t in wizard_tasks if t.status == TaskStatus.PENDING],
|
|
key=lambda t: priority_order.get(t.priority, 999)
|
|
)
|
|
|
|
# Return first non-blocked
|
|
for task in sorted_tasks:
|
|
if not task.is_blocked(completed):
|
|
return task
|
|
|
|
return None
|
|
|
|
# Singleton instance for fleet
|
|
_fleet_schema = None
|
|
|
|
def get_fleet_schema() -> FleetSchema:
|
|
global _fleet_schema
|
|
if _fleet_schema is None:
|
|
_fleet_schema = FleetSchema()
|
|
return _fleet_schema
|