Files
timmy-config/allegro/goap/self_goap.py
2026-03-31 20:02:01 +00:00

713 lines
23 KiB
Python
Executable File

#!/usr/bin/env python3
"""
GOAP Self-Integration Module - Allegro-Primus Child Autonomy System
Main integration point that connects GOAP with existing monitoring infrastructure.
Enables true autonomous behavior for the Child.
"""
import asyncio
import json
import time
import signal
import sys
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
import subprocess
import sqlite3
# GOAP components
from goals import (
GoalManager, Goal, GoalCategory, GoalPriority,
goal_manager
)
from actions import (
ActionLibrary, Action, action_library
)
from planner import (
GOAPPlanner, Plan, PlanStatus, PlanLibrary,
planner
)
from executor import (
PlanExecutor, ExecutionContext, ExecutionScheduler,
ExecutionMonitor, executor
)
@dataclass
class ChildState:
"""Complete state of the Child (Allegro-Primus)"""
timestamp: float = field(default_factory=time.time)
# System state
system: Dict[str, Any] = field(default_factory=dict)
# Knowledge state
knowledge: Dict[str, Any] = field(default_factory=dict)
# Skills state
skills: Dict[str, Any] = field(default_factory=dict)
# Social state
social: Dict[str, Any] = field(default_factory=dict)
# Performance state
performance: Dict[str, Any] = field(default_factory=dict)
# Security state
security: Dict[str, Any] = field(default_factory=dict)
# Growth state
growth: Dict[str, Any] = field(default_factory=dict)
# Data state
data: Dict[str, Any] = field(default_factory=dict)
# Adaptation state
adaptation: Dict[str, Any] = field(default_factory=dict)
def to_dict(self) -> Dict:
return {
'timestamp': self.timestamp,
'system': self.system,
'knowledge': self.knowledge,
'skills': self.skills,
'social': self.social,
'performance': self.performance,
'security': self.security,
'growth': self.growth,
'data': self.data,
'adaptation': self.adaptation
}
class WorldStateCollector:
"""Collects comprehensive world state for the Child"""
def __init__(self):
self.last_collection = 0
self.collection_interval = 60 # seconds
self.db_path = "/root/allegro/timmy_metrics.db"
def collect(self) -> ChildState:
"""Collect current world state"""
state = ChildState()
# Collect system state
state.system = self._collect_system_state()
# Collect knowledge state
state.knowledge = self._collect_knowledge_state()
# Collect skills state
state.skills = self._collect_skills_state()
# Collect social state
state.social = self._collect_social_state()
# Collect performance state
state.performance = self._collect_performance_state()
# Collect security state
state.security = self._collect_security_state()
# Collect growth state
state.growth = self._collect_growth_state()
# Collect data state
state.data = self._collect_data_state()
# Collect adaptation state
state.adaptation = self._collect_adaptation_state()
self.last_collection = time.time()
return state
def _collect_system_state(self) -> Dict:
"""Collect system metrics"""
try:
# CPU usage
cpu_result = subprocess.run(
['top', '-bn1'],
capture_output=True,
text=True,
timeout=5
)
cpu_line = [l for l in cpu_result.stdout.split('\n') if 'Cpu(s)' in l]
cpu_percent = 0
if cpu_line:
try:
cpu_str = cpu_line[0].split('%')[0].split()[-1]
cpu_percent = float(cpu_str)
except:
pass
# Memory usage
mem_result = subprocess.run(
['free', '-m'],
capture_output=True,
text=True,
timeout=5
)
mem_lines = mem_result.stdout.split('\n')
mem_percent = 0
if len(mem_lines) > 1:
try:
mem_info = mem_lines[1].split()
total = int(mem_info[1])
used = int(mem_info[2])
mem_percent = (used / total) * 100 if total > 0 else 0
except:
pass
# Disk usage
disk_result = subprocess.run(
['df', '-h', '/'],
capture_output=True,
text=True,
timeout=5
)
disk_lines = disk_result.stdout.split('\n')
disk_percent = 0
if len(disk_lines) > 1:
try:
disk_info = disk_lines[1].split()
disk_percent = int(disk_info[4].replace('%', ''))
except:
pass
# Uptime
uptime_result = subprocess.run(
['uptime', '-p'],
capture_output=True,
text=True,
timeout=5
)
uptime_str = uptime_result.stdout.strip()
uptime_hours = 0
if 'hour' in uptime_str:
try:
uptime_hours = int(uptime_str.split('hour')[0].split()[-1])
except:
pass
# Recent errors from logs
recent_errors = self._count_recent_errors()
return {
'cpu_percent': cpu_percent,
'memory_percent': mem_percent,
'disk_percent': disk_percent,
'uptime_hours': uptime_hours,
'recent_errors': recent_errors,
'timestamp': time.time()
}
except Exception as e:
return {'error': str(e), 'timestamp': time.time()}
def _collect_knowledge_state(self) -> Dict:
"""Collect knowledge metrics"""
try:
# Count knowledge files
knowledge_dir = Path("/root/allegro/research")
total_facts = 0
if knowledge_dir.exists():
total_facts = len(list(knowledge_dir.glob('**/*.md')))
# Get topics from heartbeat logs
topics = self._extract_topics_from_logs()
return {
'total_facts': total_facts,
'topics': topics,
'new_facts_per_hour': len(topics), # Simplified
'concept_connections': total_facts * 2, # Estimate
'timestamp': time.time()
}
except Exception as e:
return {'error': str(e), 'timestamp': time.time()}
def _collect_skills_state(self) -> Dict:
"""Collect skills metrics"""
try:
# Check installed skills
skills_dir = Path("/root/wizards/allegro/skills")
available = []
if skills_dir.exists():
available = [d.name for d in skills_dir.iterdir() if d.is_dir()]
# Get recently used skills from logs
recently_used = self._get_recently_used_skills()
return {
'available': available,
'proficiencies': {s: 0.7 for s in available}, # Default
'recently_used': recently_used,
'timestamp': time.time()
}
except Exception as e:
return {'error': str(e), 'timestamp': time.time()}
def _collect_social_state(self) -> Dict:
"""Collect social metrics"""
try:
# Query timmy_metrics.db for activity
active_users = 0
messages_sent = 0
if Path(self.db_path).exists():
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# Count heartbeats in last 24h
cursor.execute('''
SELECT COUNT(DISTINCT timmy_pubkey) FROM heartbeats
WHERE timestamp > datetime('now', '-1 day')
''')
result = cursor.fetchone()
active_users = result[0] if result else 0
conn.close()
except:
pass
return {
'avg_response_time': 15,
'user_satisfaction': 0.85,
'active_users': active_users,
'total_users': max(1, active_users),
'messages_sent': messages_sent,
'timestamp': time.time()
}
except Exception as e:
return {'error': str(e), 'timestamp': time.time()}
def _collect_performance_state(self) -> Dict:
"""Collect performance metrics"""
try:
# Get execution stats from executor state
executor_state_path = Path("/root/allegro/goap/executor_state.json")
if executor_state_path.exists():
with open(executor_state_path, 'r') as f:
data = json.load(f)
success_rate = data.get('total_plans_succeeded', 0) / max(1, data.get('total_plans_executed', 1))
return {
'task_success_rate': success_rate,
'time_efficiency': 0.8,
'error_rate': 1 - success_rate,
'timestamp': time.time()
}
return {
'task_success_rate': 0.8,
'time_efficiency': 0.8,
'error_rate': 0.1,
'timestamp': time.time()
}
except Exception as e:
return {'error': str(e), 'timestamp': time.time()}
def _collect_security_state(self) -> Dict:
"""Collect security metrics"""
try:
# Check last backup
backup_dir = Path("/root/backups")
last_backup_hours = 999
if backup_dir.exists():
backups = sorted(backup_dir.glob('*.tar.gz'), key=lambda p: p.stat().st_mtime, reverse=True)
if backups:
last_backup_hours = (time.time() - backups[0].stat().st_mtime) / 3600
return {
'active_alerts': [],
'credentials_valid': True,
'last_backup_hours': last_backup_hours,
'access_anomalies': 0,
'timestamp': time.time()
}
except Exception as e:
return {'error': str(e), 'timestamp': time.time()}
def _collect_growth_state(self) -> Dict:
"""Collect growth metrics"""
try:
return {
'performance_trend': 0.05,
'new_capabilities': 0,
'optimizations_found': 0,
'new_areas_explored': 0,
'experiment_success_rate': 0.5,
'discoveries': 0,
'timestamp': time.time()
}
except Exception as e:
return {'error': str(e), 'timestamp': time.time()}
def _collect_data_state(self) -> Dict:
"""Collect data metrics"""
try:
return {
'integrity_check': True,
'pending_syncs': 0,
'corruption_detected': False,
'timestamp': time.time()
}
except Exception as e:
return {'error': str(e), 'timestamp': time.time()}
def _collect_adaptation_state(self) -> Dict:
"""Collect adaptation metrics"""
try:
return {
'pattern_recognition_rate': 0.7,
'change_response_time': 60,
'accuracy_drift': 0.0,
'timestamp': time.time()
}
except Exception as e:
return {'error': str(e), 'timestamp': time.time()}
def _count_recent_errors(self) -> int:
"""Count recent errors from logs"""
try:
log_dir = Path("/root/allegro/heartbeat_logs")
if not log_dir.exists():
return 0
error_count = 0
for log_file in log_dir.glob('*.log'):
try:
with open(log_file, 'r') as f:
content = f.read()
error_count += content.count('[ERROR]')
except:
pass
return error_count
except:
return 0
def _extract_topics_from_logs(self) -> List[str]:
"""Extract research topics from logs"""
return ['system_health', 'performance', 'security']
def _get_recently_used_skills(self) -> List[str]:
"""Get recently used skills"""
return ['monitoring', 'analysis']
class SelfGOAP:
"""
Main GOAP integration class for Allegro-Primus Child.
Provides autonomous goal-directed behavior.
"""
def __init__(
self,
goal_manager: GoalManager = None,
action_library: ActionLibrary = None,
planner: GOAPPlanner = None,
executor: PlanExecutor = None
):
# Components
self.goal_manager = goal_manager or GoalManager()
self.action_library = action_library or ActionLibrary()
self.planner = planner or GOAPPlanner()
self.executor = executor or PlanExecutor()
# State collection
self.state_collector = WorldStateCollector()
self.current_state: Optional[ChildState] = None
# Scheduling
self.scheduler = ExecutionScheduler(self.executor)
self.monitor = ExecutionMonitor(self.executor)
# Configuration
self.autonomy_enabled = True
self.planning_interval = 300 # Plan every 5 minutes
self.last_planning = 0
# Logging
self.log_path = Path("/root/allegro/goap/autonomy.log")
self.log_path.parent.mkdir(parents=True, exist_ok=True)
# State persistence
self.state_file = Path("/root/allegro/goap/self_state.json")
# Running flag
self.running = False
# Load persisted state
self._load_state()
def _load_state(self):
"""Load persisted state"""
if self.state_file.exists():
try:
with open(self.state_file, 'r') as f:
data = json.load(f)
self.autonomy_enabled = data.get('autonomy_enabled', True)
self.last_planning = data.get('last_planning', 0)
except Exception as e:
self._log(f"Failed to load state: {e}")
def _save_state(self):
"""Persist state"""
try:
with open(self.state_file, 'w') as f:
json.dump({
'autonomy_enabled': self.autonomy_enabled,
'last_planning': self.last_planning,
'last_saved': time.time()
}, f, indent=2)
except Exception as e:
self._log(f"Failed to save state: {e}")
def _log(self, message: str):
"""Log message to file and stdout"""
timestamp = datetime.now().isoformat()
log_entry = f"[{timestamp}] {message}"
print(log_entry)
try:
with open(self.log_path, 'a') as f:
f.write(log_entry + '\n')
except:
pass
async def initialize(self):
"""Initialize the GOAP system"""
self._log("=== GOAP Self-System Initializing ===")
# Collect initial state
self.current_state = self.state_collector.collect()
self._log(f"Initial state collected: {len(json.dumps(self.current_state.to_dict()))} bytes")
# Update goals with current state
world_state = self.current_state.to_dict()
self.goal_manager.update_all(world_state)
self._log(f"Goals initialized: {len(self.goal_manager.goals)} goals active")
self._log(f"Actions available: {len(self.action_library.get_all())} actions")
# Start scheduler
await self.scheduler.start()
self._log("=== GOAP Self-System Ready ===")
async def run_cycle(self):
"""Run one autonomy cycle"""
if not self.autonomy_enabled:
return
# Collect current state
self.current_state = self.state_collector.collect()
world_state = self.current_state.to_dict()
# Update goals
self.goal_manager.update_all(world_state)
# Check if we should plan
time_since_planning = time.time() - self.last_planning
if time_since_planning < self.planning_interval:
return
self.last_planning = time.time()
self._save_state()
# Get active goals
active_goals = self.goal_manager.get_active_goals(threshold=0.8)
if not active_goals:
self._log("All goals satisfied - no planning needed")
return
self._log(f"Active goals: {len(active_goals)}")
for goal in active_goals[:3]:
self._log(f" - {goal.name}: satisfaction={goal.state.satisfaction:.2f}, "
f"urgency={goal.state.urgency:.2f}")
# Plan for top goal
top_goal = active_goals[0]
self._log(f"Planning for top goal: {top_goal.name}")
plan = self.planner.plan(top_goal, world_state)
if not plan:
self._log(f"No plan found for goal: {top_goal.name}")
return
self._log(f"Plan created: {len(plan.actions)} actions, "
f"estimated cost: {plan.estimated_cost}")
# Create execution context
context = ExecutionContext(
world_state=world_state,
user_context={'source': 'autonomous_cycle'},
system_context={'goal': top_goal.name}
)
# Schedule plan execution
self.scheduler.schedule(plan, context, priority=top_goal.state.effective_priority)
async def run(self):
"""Main run loop"""
self.running = True
# Initialize
await self.initialize()
self._log("=== GOAP Autonomy Loop Starting ===")
try:
while self.running:
await self.run_cycle()
# Sleep for a bit
await asyncio.sleep(10)
except asyncio.CancelledError:
self._log("Autonomy loop cancelled")
except Exception as e:
self._log(f"Error in autonomy loop: {e}")
finally:
await self.shutdown()
async def shutdown(self):
"""Shutdown the GOAP system"""
self._log("=== GOAP Self-System Shutting Down ===")
self.running = False
# Stop scheduler
await self.scheduler.stop()
# Save state
self._save_state()
self.goal_manager.save_state()
self._log("=== GOAP Self-System Shutdown Complete ===")
def get_status(self) -> Dict:
"""Get current system status"""
return {
'running': self.running,
'autonomy_enabled': self.autonomy_enabled,
'current_state': self.current_state.to_dict() if self.current_state else None,
'goals': self.goal_manager.get_stats(),
'actions': self.action_library.get_stats(),
'planner': self.planner.get_stats(),
'executor': self.executor.get_stats(),
'scheduler': self.scheduler.get_queue_status()
}
def enable_autonomy(self):
"""Enable autonomous behavior"""
self.autonomy_enabled = True
self._log("Autonomy enabled")
self._save_state()
def disable_autonomy(self):
"""Disable autonomous behavior"""
self.autonomy_enabled = False
self._log("Autonomy disabled")
self._save_state()
def force_plan(self, goal_name: Optional[str] = None) -> Optional[Plan]:
"""Force immediate planning for a goal"""
self.current_state = self.state_collector.collect()
world_state = self.current_state.to_dict()
if goal_name and goal_name in self.goal_manager.goals:
goal = self.goal_manager.goals[goal_name]
else:
goal = self.goal_manager.get_top_goal()
if not goal:
self._log("No goal available for forced planning")
return None
plan = self.planner.plan(goal, world_state)
if plan:
self._log(f"Forced plan created: {len(plan.actions)} actions for {goal.name}")
return plan
# =============================================================================
# CLI INTERFACE
# =============================================================================
async def main():
"""Main entry point"""
import argparse
parser = argparse.ArgumentParser(description='Allegro-Primus GOAP Autonomy System')
parser.add_argument('--run', action='store_true', help='Run autonomy loop')
parser.add_argument('--status', action='store_true', help='Show status')
parser.add_argument('--enable', action='store_true', help='Enable autonomy')
parser.add_argument('--disable', action='store_true', help='Disable autonomy')
parser.add_argument('--plan', type=str, help='Force plan for goal')
parser.add_argument('--once', action='store_true', help='Run one cycle and exit')
args = parser.parse_args()
# Create GOAP system
goap = SelfGOAP()
if args.status:
status = goap.get_status()
print(json.dumps(status, indent=2, default=str))
elif args.enable:
goap.enable_autonomy()
print("Autonomy enabled")
elif args.disable:
goap.disable_autonomy()
print("Autonomy disabled")
elif args.plan:
plan = goap.force_plan(args.plan)
if plan:
print(f"Plan for {plan.goal.name}:")
for i, action in enumerate(plan.actions):
print(f" {i+1}. {action.name}")
else:
print("No plan found")
elif args.once:
await goap.initialize()
await goap.run_cycle()
await goap.shutdown()
elif args.run:
# Set up signal handlers
goap_system = goap
def signal_handler(sig, frame):
print("\nReceived shutdown signal")
asyncio.create_task(goap_system.shutdown())
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
# Run
await goap.run()
else:
parser.print_help()
# Singleton instance for import
self_goap = SelfGOAP()
if __name__ == "__main__":
asyncio.run(main())