1054 lines
36 KiB
Python
Executable File
1054 lines
36 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
GOAP Actions Module - Allegro-Primus Child Autonomy System
|
|
Defines all available actions with preconditions and effects.
|
|
"""
|
|
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass, field
|
|
from typing import Dict, List, Optional, Callable, Any, Set, Union
|
|
from enum import Enum, auto
|
|
import time
|
|
import json
|
|
import subprocess
|
|
import asyncio
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
|
|
class ActionStatus(Enum):
|
|
"""Status of an action"""
|
|
PENDING = auto()
|
|
RUNNING = auto()
|
|
SUCCESS = auto()
|
|
FAILED = auto()
|
|
CANCELLED = auto()
|
|
|
|
|
|
@dataclass
|
|
class ActionResult:
|
|
"""Result of executing an action"""
|
|
success: bool
|
|
status: ActionStatus
|
|
message: str = ""
|
|
effects_applied: Dict[str, Any] = field(default_factory=dict)
|
|
execution_time: float = 0.0
|
|
error: Optional[str] = None
|
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
|
|
@classmethod
|
|
def success_result(cls, message: str = "", effects: Dict = None, **kwargs):
|
|
return cls(
|
|
success=True,
|
|
status=ActionStatus.SUCCESS,
|
|
message=message,
|
|
effects_applied=effects or {},
|
|
**kwargs
|
|
)
|
|
|
|
@classmethod
|
|
def failure_result(cls, error: str, message: str = "", **kwargs):
|
|
return cls(
|
|
success=False,
|
|
status=ActionStatus.FAILED,
|
|
message=message or error,
|
|
error=error,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class Action(ABC):
|
|
"""Abstract base class for all actions"""
|
|
|
|
def __init__(
|
|
self,
|
|
name: str,
|
|
cost: float = 1.0,
|
|
preconditions: Optional[Dict[str, Any]] = None,
|
|
effects: Optional[Dict[str, Any]] = None,
|
|
category: str = "general"
|
|
):
|
|
self.name = name
|
|
self.cost = cost
|
|
self.preconditions = preconditions or {}
|
|
self.effects = effects or {}
|
|
self.category = category
|
|
self.execution_count = 0
|
|
self.success_count = 0
|
|
self.total_execution_time = 0.0
|
|
|
|
def check_preconditions(self, world_state: Dict[str, Any]) -> bool:
|
|
"""Check if preconditions are met"""
|
|
for key, expected_value in self.preconditions.items():
|
|
actual_value = self._get_nested_value(world_state, key)
|
|
if not self._compare_values(actual_value, expected_value):
|
|
return False
|
|
return True
|
|
|
|
def get_unmet_preconditions(self, world_state: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""Get list of unmet preconditions"""
|
|
unmet = {}
|
|
for key, expected_value in self.preconditions.items():
|
|
actual_value = self._get_nested_value(world_state, key)
|
|
if not self._compare_values(actual_value, expected_value):
|
|
unmet[key] = {'expected': expected_value, 'actual': actual_value}
|
|
return unmet
|
|
|
|
def apply_effects(self, world_state: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""Apply effects to world state (returns new state)"""
|
|
new_state = self._deep_copy(world_state)
|
|
for key, effect_value in self.effects.items():
|
|
self._set_nested_value(new_state, key, effect_value)
|
|
return new_state
|
|
|
|
@abstractmethod
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
"""Execute the action in the real world"""
|
|
pass
|
|
|
|
def _get_nested_value(self, d: Dict, key: str) -> Any:
|
|
"""Get value from nested dict using dot notation"""
|
|
keys = key.split('.')
|
|
value = d
|
|
for k in keys:
|
|
if isinstance(value, dict):
|
|
value = value.get(k)
|
|
else:
|
|
return None
|
|
return value
|
|
|
|
def _set_nested_value(self, d: Dict, key: str, value: Any):
|
|
"""Set value in nested dict using dot notation"""
|
|
keys = key.split('.')
|
|
current = d
|
|
for k in keys[:-1]:
|
|
if k not in current:
|
|
current[k] = {}
|
|
current = current[k]
|
|
current[keys[-1]] = value
|
|
|
|
def _compare_values(self, actual: Any, expected: Any) -> bool:
|
|
"""Compare actual vs expected values with type coercion"""
|
|
if isinstance(expected, dict) and '_operator' in expected:
|
|
op = expected['_operator']
|
|
target = expected['_value']
|
|
|
|
if op == 'gt':
|
|
try:
|
|
return actual is not None and float(actual) > float(target)
|
|
except (TypeError, ValueError):
|
|
return False
|
|
elif op == 'gte':
|
|
try:
|
|
return actual is not None and float(actual) >= float(target)
|
|
except (TypeError, ValueError):
|
|
return False
|
|
elif op == 'lt':
|
|
try:
|
|
return actual is not None and float(actual) < float(target)
|
|
except (TypeError, ValueError):
|
|
return False
|
|
elif op == 'lte':
|
|
try:
|
|
return actual is not None and float(actual) <= float(target)
|
|
except (TypeError, ValueError):
|
|
return False
|
|
elif op == 'exists':
|
|
return actual is not None if target else actual is None
|
|
elif op == 'contains':
|
|
return target in actual if isinstance(actual, (list, str)) else False
|
|
elif op == 'not_empty':
|
|
return bool(actual) if target else True
|
|
|
|
return actual == expected
|
|
|
|
def _deep_copy(self, d: Dict) -> Dict:
|
|
"""Deep copy a dict"""
|
|
return json.loads(json.dumps(d))
|
|
|
|
def to_dict(self) -> Dict:
|
|
return {
|
|
'name': self.name,
|
|
'cost': self.cost,
|
|
'category': self.category,
|
|
'preconditions': self.preconditions,
|
|
'effects': self.effects,
|
|
'execution_count': self.execution_count,
|
|
'success_count': self.success_count,
|
|
'success_rate': self.success_count / max(1, self.execution_count),
|
|
'avg_execution_time': self.total_execution_time / max(1, self.execution_count)
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# SYSTEM ACTIONS - Health, Maintenance, Security
|
|
# =============================================================================
|
|
|
|
class CheckSystemHealth(Action):
|
|
"""Check overall system health"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="check_system_health",
|
|
cost=1.0,
|
|
preconditions={},
|
|
effects={
|
|
'system.health_checked': True,
|
|
'system.last_check_time': time.time()
|
|
},
|
|
category="system"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
try:
|
|
# Check disk space
|
|
df_result = subprocess.run(
|
|
['df', '-h', '/'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=10
|
|
)
|
|
|
|
# Check memory
|
|
mem_result = subprocess.run(
|
|
['free', '-m'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=10
|
|
)
|
|
|
|
# Check load
|
|
load_result = subprocess.run(
|
|
['uptime'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=10
|
|
)
|
|
|
|
execution_time = time.time() - start_time
|
|
|
|
return ActionResult.success_result(
|
|
message="System health check completed",
|
|
effects={
|
|
'system.health_status': 'checked',
|
|
'system.disk_info': df_result.stdout,
|
|
'system.memory_info': mem_result.stdout,
|
|
'system.load_info': load_result.stdout
|
|
},
|
|
execution_time=execution_time,
|
|
metadata={'checks_performed': 3}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message="System health check failed",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
class CleanupResources(Action):
|
|
"""Clean up temporary files and resources"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="cleanup_resources",
|
|
cost=2.0,
|
|
preconditions={
|
|
'system.disk_percent': {'_operator': 'gt', '_value': 70}
|
|
},
|
|
effects={
|
|
'system.disk_percent': 60.0,
|
|
'system.temp_files_cleaned': True
|
|
},
|
|
category="system"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
cleaned_count = 0
|
|
freed_bytes = 0
|
|
|
|
try:
|
|
# Clean temp directories
|
|
temp_dirs = ['/tmp', '/var/tmp', '/root/.cache']
|
|
|
|
for temp_dir in temp_dirs:
|
|
if Path(temp_dir).exists():
|
|
# Find files older than 7 days
|
|
result = subprocess.run(
|
|
['find', temp_dir, '-type', 'f', '-mtime', '+7', '-ls'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=30
|
|
)
|
|
|
|
if result.stdout:
|
|
# Remove old files
|
|
rm_result = subprocess.run(
|
|
['find', temp_dir, '-type', 'f', '-mtime', '+7', '-delete'],
|
|
capture_output=True,
|
|
timeout=60
|
|
)
|
|
cleaned_count += len(result.stdout.strip().split('\n'))
|
|
|
|
# Clean Docker if available
|
|
try:
|
|
docker_result = subprocess.run(
|
|
['docker', 'system', 'prune', '-f'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60
|
|
)
|
|
if docker_result.returncode == 0:
|
|
freed_bytes += 1024 * 1024 * 100 # Estimate 100MB
|
|
except:
|
|
pass
|
|
|
|
execution_time = time.time() - start_time
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Cleaned up {cleaned_count} old files",
|
|
effects={
|
|
'system.temp_files_cleaned': True,
|
|
'system.cleanup_count': cleaned_count,
|
|
'system.freed_bytes': freed_bytes
|
|
},
|
|
execution_time=execution_time
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message="Resource cleanup failed",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
class RestartService(Action):
|
|
"""Restart a failing service"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="restart_service",
|
|
cost=3.0,
|
|
preconditions={
|
|
'services.failing': {'_operator': 'not_empty', '_value': True}
|
|
},
|
|
effects={
|
|
'services.failing': [],
|
|
'services.restarted': True
|
|
},
|
|
category="system"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
service_name = context.get('target_service', 'unknown')
|
|
|
|
try:
|
|
# Try systemctl restart
|
|
result = subprocess.run(
|
|
['systemctl', 'restart', service_name],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=30
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
# Verify service is running
|
|
check_result = subprocess.run(
|
|
['systemctl', 'is-active', service_name],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=10
|
|
)
|
|
|
|
is_active = check_result.stdout.strip() == 'active'
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Service {service_name} restarted successfully",
|
|
effects={
|
|
'services.status': {service_name: 'active'},
|
|
'services.restart_success': is_active
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'service': service_name, 'active': is_active}
|
|
)
|
|
else:
|
|
return ActionResult.failure_result(
|
|
error=result.stderr,
|
|
message=f"Failed to restart {service_name}",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message=f"Service restart failed for {service_name}",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
class BackupData(Action):
|
|
"""Perform data backup"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="backup_data",
|
|
cost=5.0,
|
|
preconditions={
|
|
'system.disk_percent': {'_operator': 'lt', '_value': 90}
|
|
},
|
|
effects={
|
|
'security.last_backup_hours': 0,
|
|
'data.backup_complete': True
|
|
},
|
|
category="system"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
backup_path = f"/root/backups/backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
|
|
|
try:
|
|
Path(backup_path).mkdir(parents=True, exist_ok=True)
|
|
|
|
# Backup critical data
|
|
critical_dirs = ['/root/allegro', '/root/wizards']
|
|
|
|
for source in critical_dirs:
|
|
if Path(source).exists():
|
|
result = subprocess.run(
|
|
['rsync', '-avz', '--delete', source, backup_path],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300
|
|
)
|
|
|
|
# Create archive
|
|
archive_name = f"{backup_path}.tar.gz"
|
|
result = subprocess.run(
|
|
['tar', '-czf', archive_name, '-C', '/root/backups', Path(backup_path).name],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=120
|
|
)
|
|
|
|
# Clean up temp backup dir
|
|
subprocess.run(['rm', '-rf', backup_path], timeout=30)
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Backup created: {archive_name}",
|
|
effects={
|
|
'security.last_backup_hours': 0,
|
|
'security.last_backup_path': archive_name,
|
|
'data.backup_complete': True
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'backup_path': archive_name}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message="Backup failed",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
# =============================================================================
|
|
# KNOWLEDGE ACTIONS - Learning and Information Gathering
|
|
# =============================================================================
|
|
|
|
class ResearchTopic(Action):
|
|
"""Research a topic to gain knowledge"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="research_topic",
|
|
cost=4.0,
|
|
preconditions={
|
|
'system.cpu_percent': {'_operator': 'lt', '_value': 80}
|
|
},
|
|
effects={
|
|
'knowledge.new_facts_per_hour': {'_operator': 'gt', '_value': 5},
|
|
'knowledge.research_completed': True
|
|
},
|
|
category="knowledge"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
topic = context.get('topic', 'general')
|
|
|
|
try:
|
|
# Use web search tool if available
|
|
search_query = context.get('query', f"latest developments in {topic}")
|
|
|
|
# Simulate research (in production, would use actual search)
|
|
research_results = {
|
|
'topic': topic,
|
|
'sources_found': 5,
|
|
'key_findings': [f"Finding about {topic}" for _ in range(3)],
|
|
'confidence': 0.8
|
|
}
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Research completed on: {topic}",
|
|
effects={
|
|
'knowledge.topics': [topic],
|
|
'knowledge.research_results': research_results,
|
|
'knowledge.new_facts_per_hour': 8
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'topic': topic, 'sources': 5}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message=f"Research failed for topic: {topic}",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
class IndexKnowledge(Action):
|
|
"""Index and organize knowledge"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="index_knowledge",
|
|
cost=3.0,
|
|
preconditions={
|
|
'knowledge.research_completed': True
|
|
},
|
|
effects={
|
|
'knowledge.concept_connections': {'_operator': 'gt', '_value': 100},
|
|
'knowledge.indexed': True
|
|
},
|
|
category="knowledge"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
|
|
try:
|
|
# Process research results and create connections
|
|
research_data = context.get('research_results', {})
|
|
|
|
# Simulate indexing
|
|
connections_created = 50
|
|
concepts_linked = 10
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Knowledge indexed: {connections_created} connections created",
|
|
effects={
|
|
'knowledge.concept_connections': connections_created,
|
|
'knowledge.indexed': True,
|
|
'knowledge.index_time': time.time()
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'connections': connections_created, 'concepts': concepts_linked}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message="Knowledge indexing failed",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
class LearnFromInteraction(Action):
|
|
"""Learn from user interactions"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="learn_from_interaction",
|
|
cost=2.0,
|
|
preconditions={},
|
|
effects={
|
|
'social.preferences_learned': {'_operator': 'gt', '_value': 0},
|
|
'adaptation.pattern_recognition_rate': 0.75
|
|
},
|
|
category="knowledge"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
|
|
try:
|
|
interaction_data = context.get('interaction', {})
|
|
user_id = interaction_data.get('user_id', 'unknown')
|
|
feedback = interaction_data.get('feedback', 'neutral')
|
|
|
|
# Extract preferences
|
|
preferences_learned = 1
|
|
pattern_updated = True
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Learned from interaction with user {user_id}",
|
|
effects={
|
|
'social.preferences_learned': preferences_learned,
|
|
'social.user_preferences': {user_id: {'feedback': feedback}},
|
|
'adaptation.pattern_recognition_rate': 0.75
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'user': user_id, 'feedback': feedback}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message="Learning from interaction failed",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
# =============================================================================
|
|
# SKILL ACTIONS - Skill Development and Usage
|
|
# =============================================================================
|
|
|
|
class PracticeSkill(Action):
|
|
"""Practice a skill to improve proficiency"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="practice_skill",
|
|
cost=3.0,
|
|
preconditions={
|
|
'skills.available': {'_operator': 'not_empty', '_value': True}
|
|
},
|
|
effects={
|
|
'skills.avg_proficiency': {'_operator': 'gt', '_value': 0.6},
|
|
'skills.practice_completed': True
|
|
},
|
|
category="skills"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
skill_name = context.get('skill', 'general')
|
|
|
|
try:
|
|
# Simulate skill practice
|
|
proficiency_gain = 0.05
|
|
practice_duration = 300 # seconds
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Practiced skill: {skill_name}",
|
|
effects={
|
|
'skills.proficiencies': {skill_name: 0.7},
|
|
'skills.practice_completed': True,
|
|
'skills.last_practiced': skill_name
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'skill': skill_name, 'gain': proficiency_gain}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message=f"Skill practice failed for {skill_name}",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
class AcquireNewSkill(Action):
|
|
"""Acquire a new skill"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="acquire_new_skill",
|
|
cost=8.0,
|
|
preconditions={
|
|
'knowledge.concept_connections': {'_operator': 'gt', '_value': 50}
|
|
},
|
|
effects={
|
|
'skills.available': {'_operator': 'contains', '_value': 'new_skill'},
|
|
'growth.new_capabilities': 1
|
|
},
|
|
category="skills"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
new_skill = context.get('new_skill', 'unknown_skill')
|
|
|
|
try:
|
|
# Install or acquire the new skill
|
|
return ActionResult.success_result(
|
|
message=f"Acquired new skill: {new_skill}",
|
|
effects={
|
|
'skills.available': [new_skill],
|
|
'skills.proficiencies': {new_skill: 0.3},
|
|
'growth.new_capabilities': 1
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'skill': new_skill}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message=f"Failed to acquire skill: {new_skill}",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
# =============================================================================
|
|
# SOCIAL ACTIONS - User Engagement and Communication
|
|
# =============================================================================
|
|
|
|
class SendMessage(Action):
|
|
"""Send a message to a user"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="send_message",
|
|
cost=1.0,
|
|
preconditions={
|
|
'social.active_users': {'_operator': 'gt', '_value': 0}
|
|
},
|
|
effects={
|
|
'social.last_message_sent': time.time(),
|
|
'social.engagement_count': {'_operator': 'gt', '_value': 0}
|
|
},
|
|
category="social"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
recipient = context.get('recipient', 'user')
|
|
message = context.get('message', 'Hello!')
|
|
platform = context.get('platform', 'telegram')
|
|
|
|
try:
|
|
# In production, would call actual message sending
|
|
return ActionResult.success_result(
|
|
message=f"Message sent to {recipient} via {platform}",
|
|
effects={
|
|
'social.last_message_time': time.time(),
|
|
'social.messages_sent': 1,
|
|
'social.last_recipient': recipient
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'recipient': recipient, 'platform': platform, 'length': len(message)}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message="Failed to send message",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
class ProactiveCheckIn(Action):
|
|
"""Proactively check in with users"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="proactive_check_in",
|
|
cost=2.0,
|
|
preconditions={
|
|
'social.proactive_ratio': {'_operator': 'lt', '_value': 0.5}
|
|
},
|
|
effects={
|
|
'social.proactive_ratio': {'_operator': 'gt', '_value': 0.3},
|
|
'social.check_in_completed': True
|
|
},
|
|
category="social"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
|
|
try:
|
|
# Generate check-in message based on context
|
|
user_context = context.get('user_context', {})
|
|
last_interaction = user_context.get('last_interaction_hours', 24)
|
|
|
|
if last_interaction > 24:
|
|
message = "Hey! Haven't heard from you in a while. How are things going?"
|
|
else:
|
|
message = "Just checking in! Is there anything I can help with?"
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Proactive check-in sent",
|
|
effects={
|
|
'social.proactive_ratio': 0.4,
|
|
'social.check_in_completed': True,
|
|
'social.last_check_in': time.time()
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'message': message, 'last_interaction_hours': last_interaction}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message="Proactive check-in failed",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
class ShareKnowledge(Action):
|
|
"""Share knowledge with other agents/systems"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="share_knowledge",
|
|
cost=2.0,
|
|
preconditions={
|
|
'knowledge.concept_connections': {'_operator': 'gt', '_value': 20}
|
|
},
|
|
effects={
|
|
'social.shared_knowledge_usage': {'_operator': 'gt', '_value': 0.5},
|
|
'collaboration.knowledge_shared': True
|
|
},
|
|
category="social"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
target_system = context.get('target_system', 'default')
|
|
|
|
try:
|
|
knowledge_to_share = context.get('knowledge', {})
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Knowledge shared with {target_system}",
|
|
effects={
|
|
'social.shared_knowledge_usage': 0.7,
|
|
'collaboration.knowledge_shared': True,
|
|
'collaboration.last_share_time': time.time()
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'target': target_system, 'items_shared': len(knowledge_to_share)}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message="Knowledge sharing failed",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
# =============================================================================
|
|
# GROWTH ACTIONS - Self-Improvement and Exploration
|
|
# =============================================================================
|
|
|
|
class SelfAnalysis(Action):
|
|
"""Analyze own performance for improvement opportunities"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="self_analysis",
|
|
cost=3.0,
|
|
preconditions={},
|
|
effects={
|
|
'growth.performance_trend': 0.05,
|
|
'growth.optimizations_found': {'_operator': 'gt', '_value': 0}
|
|
},
|
|
category="growth"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
|
|
try:
|
|
# Analyze recent performance
|
|
performance_data = context.get('performance_history', [])
|
|
|
|
# Find optimization opportunities
|
|
optimizations = [
|
|
'Reduce API call latency by batching',
|
|
'Cache frequently accessed knowledge',
|
|
'Optimize database queries'
|
|
]
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Self-analysis complete: {len(optimizations)} optimizations found",
|
|
effects={
|
|
'growth.optimizations_found': len(optimizations),
|
|
'growth.optimization_list': optimizations,
|
|
'growth.performance_trend': 0.08
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'optimizations': len(optimizations)}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message="Self-analysis failed",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
class Experiment(Action):
|
|
"""Run an experiment to test new approaches"""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="experiment",
|
|
cost=5.0,
|
|
preconditions={
|
|
'system.cpu_percent': {'_operator': 'lt', '_value': 70}
|
|
},
|
|
effects={
|
|
'growth.experiment_completed': True,
|
|
'growth.new_areas_explored': 1
|
|
},
|
|
category="growth"
|
|
)
|
|
|
|
async def execute(self, context: Dict[str, Any]) -> ActionResult:
|
|
start_time = time.time()
|
|
experiment_type = context.get('experiment_type', 'default')
|
|
|
|
try:
|
|
# Run experiment
|
|
success = True
|
|
findings = f"Findings from {experiment_type} experiment"
|
|
|
|
return ActionResult.success_result(
|
|
message=f"Experiment '{experiment_type}' completed",
|
|
effects={
|
|
'growth.experiment_completed': True,
|
|
'growth.experiment_success_rate': 0.7 if success else 0.3,
|
|
'growth.new_areas_explored': 1,
|
|
'growth.last_experiment_findings': findings
|
|
},
|
|
execution_time=time.time() - start_time,
|
|
metadata={'type': experiment_type, 'success': success}
|
|
)
|
|
except Exception as e:
|
|
return ActionResult.failure_result(
|
|
error=str(e),
|
|
message=f"Experiment failed: {experiment_type}",
|
|
execution_time=time.time() - start_time
|
|
)
|
|
|
|
|
|
# =============================================================================
|
|
# ACTION LIBRARY
|
|
# =============================================================================
|
|
|
|
class ActionLibrary:
|
|
"""Registry of all available actions"""
|
|
|
|
def __init__(self):
|
|
self.actions: Dict[str, Action] = {}
|
|
self._register_default_actions()
|
|
|
|
def _register_default_actions(self):
|
|
"""Register all default actions"""
|
|
actions = [
|
|
# System actions
|
|
CheckSystemHealth(),
|
|
CleanupResources(),
|
|
RestartService(),
|
|
BackupData(),
|
|
|
|
# Knowledge actions
|
|
ResearchTopic(),
|
|
IndexKnowledge(),
|
|
LearnFromInteraction(),
|
|
|
|
# Skill actions
|
|
PracticeSkill(),
|
|
AcquireNewSkill(),
|
|
|
|
# Social actions
|
|
SendMessage(),
|
|
ProactiveCheckIn(),
|
|
ShareKnowledge(),
|
|
|
|
# Growth actions
|
|
SelfAnalysis(),
|
|
Experiment(),
|
|
]
|
|
|
|
for action in actions:
|
|
self.register(action)
|
|
|
|
def register(self, action: Action):
|
|
"""Register an action"""
|
|
self.actions[action.name] = action
|
|
|
|
def get(self, name: str) -> Optional[Action]:
|
|
"""Get an action by name"""
|
|
return self.actions.get(name)
|
|
|
|
def get_all(self) -> List[Action]:
|
|
"""Get all actions"""
|
|
return list(self.actions.values())
|
|
|
|
def get_by_category(self, category: str) -> List[Action]:
|
|
"""Get actions by category"""
|
|
return [a for a in self.actions.values() if a.category == category]
|
|
|
|
def get_applicable(self, world_state: Dict[str, Any]) -> List[Action]:
|
|
"""Get actions that can be applied in current world state"""
|
|
return [a for a in self.actions.values() if a.check_preconditions(world_state)]
|
|
|
|
def get_stats(self) -> Dict:
|
|
"""Get action library statistics"""
|
|
return {
|
|
'total_actions': len(self.actions),
|
|
'by_category': {
|
|
cat: len(self.get_by_category(cat))
|
|
for cat in set(a.category for a in self.actions.values())
|
|
},
|
|
'most_used': sorted(
|
|
self.actions.values(),
|
|
key=lambda a: a.execution_count,
|
|
reverse=True
|
|
)[:5],
|
|
'highest_success_rate': sorted(
|
|
self.actions.values(),
|
|
key=lambda a: a.success_count / max(1, a.execution_count),
|
|
reverse=True
|
|
)[:5]
|
|
}
|
|
|
|
def to_dict(self) -> Dict:
|
|
"""Export action library data"""
|
|
return {
|
|
'actions': {name: action.to_dict() for name, action in self.actions.items()},
|
|
'stats': self.get_stats()
|
|
}
|
|
|
|
|
|
# Singleton instance
|
|
action_library = ActionLibrary()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Test the actions module
|
|
print("=== GOAP Actions Module Test ===")
|
|
|
|
library = ActionLibrary()
|
|
|
|
print("\n=== Available Actions ===")
|
|
for action in library.get_all():
|
|
print(f"- {action.name} (category: {action.category}, cost: {action.cost})")
|
|
|
|
print("\n=== Action Statistics ===")
|
|
stats = library.get_stats()
|
|
print(f"Total actions: {stats['total_actions']}")
|
|
print(f"By category: {stats['by_category']}")
|
|
|
|
# Test precondition checking
|
|
print("\n=== Precondition Test ===")
|
|
world_state = {
|
|
'system': {
|
|
'cpu_percent': 60,
|
|
'disk_percent': 75,
|
|
'memory_percent': 50
|
|
},
|
|
'services': {
|
|
'failing': ['test_service']
|
|
},
|
|
'knowledge': {
|
|
'concept_connections': 100
|
|
}
|
|
}
|
|
|
|
applicable = library.get_applicable(world_state)
|
|
print(f"Applicable actions in current state: {len(applicable)}")
|
|
for action in applicable:
|
|
print(f" - {action.name}")
|