Initial commit: Natiris AI Agent Orchestration System
This commit is contained in:
370
agents/natiris_recovery_agent.py
Normal file
370
agents/natiris_recovery_agent.py
Normal file
@@ -0,0 +1,370 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Natiris Recovery Agent – Status-Tracker und Wiederanlauf
|
||||
Überwacht den Projektstatus und ermöglicht nahtlose Fortsetzung
|
||||
|
||||
Features:
|
||||
- Status-Tracking nach jedem Schritt
|
||||
- Checkpoint-System für Unterbrechungen
|
||||
- Automatischer Resume nach Token-Limit/Neustart
|
||||
- Fortschrittsbericht generierung
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
PROJECT_ROOT = os.path.expanduser("~/natiris")
|
||||
STATE_FILE = os.path.join(PROJECT_ROOT, "agent_state.json")
|
||||
CHECKPOINT_FILE = os.path.join(PROJECT_ROOT, "checkpoints", "latest.json")
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
requests = None
|
||||
|
||||
def log(msg, level="INFO"):
|
||||
"""Log mit Timestamp"""
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
print(f"[{timestamp}] [{level}] {msg}")
|
||||
|
||||
# Auch in Log-Datei
|
||||
log_file = os.path.join(PROJECT_ROOT, "agent_recovery.log")
|
||||
with open(log_file, "a") as f:
|
||||
f.write(f"[{timestamp}] [{level}] {msg}\n")
|
||||
|
||||
class NatirisRecoveryAgent:
|
||||
"""
|
||||
Verwaltet den Zustand des Natiris-Projekts
|
||||
und ermöglicht Wiederanlauf nach Unterbrechungen
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.project_root = Path(PROJECT_ROOT)
|
||||
self.checkpoints_dir = self.project_root / "checkpoints"
|
||||
self.checkpoints_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Aktueller Zustand
|
||||
self.state = self.load_state()
|
||||
|
||||
# Task-Queue (was als nächstes zu tun ist)
|
||||
self.task_queue = []
|
||||
|
||||
def load_state(self):
|
||||
"""Lädt den aktuellen Agent-State"""
|
||||
if os.path.exists(STATE_FILE):
|
||||
try:
|
||||
with open(STATE_FILE) as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
return self.get_default_state()
|
||||
return self.get_default_state()
|
||||
|
||||
def get_default_state(self):
|
||||
"""Standard-Zustand für neuen Start"""
|
||||
return {
|
||||
"phase": "initialization",
|
||||
"last_action": None,
|
||||
"last_action_time": None,
|
||||
"completed_tasks": [],
|
||||
"pending_tasks": [
|
||||
"update_comfybridge_with_ipadapter",
|
||||
"test_ipadapter_integration",
|
||||
"integrate_vision_loop",
|
||||
"optimize_natural_language",
|
||||
"final_testing",
|
||||
"documentation"
|
||||
],
|
||||
"checkpoint_count": 0,
|
||||
"last_error": None,
|
||||
"session_count": 0
|
||||
}
|
||||
|
||||
def save_state(self):
|
||||
"""Speichert aktuellen Zustand"""
|
||||
self.state["last_action_time"] = datetime.now().isoformat()
|
||||
|
||||
with open(STATE_FILE, "w") as f:
|
||||
json.dump(self.state, f, indent=2)
|
||||
|
||||
# Zusätzlich als Checkpoint
|
||||
checkpoint_id = self.state.get("checkpoint_count", 0) + 1
|
||||
checkpoint_file = self.checkpoints_dir / f"checkpoint_{checkpoint_id:04d}.json"
|
||||
|
||||
with open(checkpoint_file, "w") as f:
|
||||
json.dump(self.state, f, indent=2)
|
||||
|
||||
self.state["checkpoint_count"] = checkpoint_id
|
||||
log(f"State saved (checkpoint {checkpoint_id})")
|
||||
|
||||
def mark_task_complete(self, task_name, details=None):
|
||||
"""Markiert eine Task als abgeschlossen"""
|
||||
if task_name in self.state["pending_tasks"]:
|
||||
self.state["pending_tasks"].remove(task_name)
|
||||
|
||||
completion_entry = {
|
||||
"task": task_name,
|
||||
"completed_at": datetime.now().isoformat(),
|
||||
"details": details or {}
|
||||
}
|
||||
|
||||
self.state["completed_tasks"].append(completion_entry)
|
||||
self.state["last_action"] = f"completed_{task_name}"
|
||||
|
||||
log(f"Task completed: {task_name}")
|
||||
self.save_state()
|
||||
|
||||
def set_phase(self, phase_name):
|
||||
"""Setzt aktuelle Phase"""
|
||||
self.state["phase"] = phase_name
|
||||
self.state["last_action"] = f"phase_change_{phase_name}"
|
||||
log(f"Phase changed to: {phase_name}")
|
||||
self.save_state()
|
||||
|
||||
def record_error(self, error_msg):
|
||||
"""Speichert Fehler für spätere Analyse"""
|
||||
self.state["last_error"] = {
|
||||
"message": str(error_msg),
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"phase": self.state["phase"]
|
||||
}
|
||||
self.save_state()
|
||||
log(f"ERROR recorded: {error_msg}", level="ERROR")
|
||||
|
||||
def get_next_task(self):
|
||||
"""Liefert nächste zu erledigende Task"""
|
||||
if self.state["pending_tasks"]:
|
||||
return self.state["pending_tasks"][0]
|
||||
return None
|
||||
|
||||
def get_progress_report(self):
|
||||
"""Generiert Fortschrittsbericht"""
|
||||
total = len(self.state["completed_tasks"]) + len(self.state["pending_tasks"])
|
||||
completed = len(self.state["completed_tasks"])
|
||||
|
||||
if total > 0:
|
||||
percent = (completed / total) * 100
|
||||
else:
|
||||
percent = 0
|
||||
|
||||
report = f"""
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ NATIRIS RECOVERY AGENT - STATUS REPORT ║
|
||||
╠══════════════════════════════════════════════════════════════╣
|
||||
║ Current Phase: {self.state['phase']:<38} ║
|
||||
║ Last Action: {str(self.state['last_action'])[:38]:<38} ║
|
||||
║ Checkpoints: {self.state['checkpoint_count']:<38} ║
|
||||
║ Progress: {completed}/{total} ({percent:.1f}%) {'█' * int(percent/5):<20} ║
|
||||
╠══════════════════════════════════════════════════════════════╣
|
||||
║ PENDING TASKS: ║
|
||||
"""
|
||||
for i, task in enumerate(self.state["pending_tasks"][:5], 1):
|
||||
report += f"║ {i}. {task[:50]:<51} ║\n"
|
||||
|
||||
if len(self.state["pending_tasks"]) > 5:
|
||||
report += f"║ ... and {len(self.state['pending_tasks']) - 5} more{'':<36} ║\n"
|
||||
|
||||
report += """╠══════════════════════════════════════════════════════════════╣
|
||||
║ RECENTLY COMPLETED: ║
|
||||
"""
|
||||
recent = self.state["completed_tasks"][-3:]
|
||||
for entry in recent:
|
||||
task = entry["task"]
|
||||
time_str = entry["completed_at"][11:19] # HH:MM:SS
|
||||
report += f"║ ✓ {task[:20]:<20} at {time_str:<24} ║\n"
|
||||
|
||||
if not recent:
|
||||
report += f"║ (none yet){'':<47} ║\n"
|
||||
|
||||
report += """╚══════════════════════════════════════════════════════════════╝
|
||||
"""
|
||||
return report
|
||||
|
||||
def generate_resume_instructions(self):
|
||||
"""Generiert Befehle für Wiederanlauf"""
|
||||
next_task = self.get_next_task()
|
||||
|
||||
instructions = f"""
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ NATIRIS RESUME INSTRUCTIONS ║
|
||||
╠══════════════════════════════════════════════════════════════╣
|
||||
|
||||
Current Status:
|
||||
Phase: {self.state['phase']}
|
||||
Last Action: {self.state['last_action']}
|
||||
Pending Tasks: {len(self.state['pending_tasks'])}
|
||||
|
||||
NEXT IMMEDIATE TASK:
|
||||
→ {next_task or 'ALL TASKS COMPLETED'}
|
||||
|
||||
QUICK START COMMANDS:
|
||||
"""
|
||||
if next_task == "update_comfybridge_with_ipadapter":
|
||||
instructions += """
|
||||
1. Update ComfyBridge with correct IPAdapter paths:
|
||||
cd ~/natiris && nano bridges/ComfyBridge.py
|
||||
- Update MODEL_PATHS with correct paths
|
||||
- Test with: python3 bridges/ComfyBridge.py --test
|
||||
|
||||
2. Verify IPAdapter models exist:
|
||||
ls /opt/pinokio/drive/drives/peers/d1753059260169/ipadapter/
|
||||
"""
|
||||
elif next_task == "test_ipadapter_integration":
|
||||
instructions += """
|
||||
1. Generate test image with IPAdapter:
|
||||
cd ~/natiris && python3 bridges/ComfyBridge.py --test
|
||||
|
||||
2. Check if image was generated with face consistency:
|
||||
ls -la ~/natiris/generated/
|
||||
"""
|
||||
elif next_task == "integrate_vision_loop":
|
||||
instructions += """
|
||||
1. Connect VisionBridge to Core:
|
||||
- Update Orchestrator to trigger Vision after ComfyBridge
|
||||
- Test full loop: Text → Image → Vision → Response
|
||||
|
||||
2. Verify state updates:
|
||||
cat ~/natiris/core/natiris_full_state.json
|
||||
"""
|
||||
|
||||
instructions += """
|
||||
TO CONTINUE WHERE YOU LEFT OFF:
|
||||
python3 ~/natiris/agents/natiris_recovery_agent.py --resume
|
||||
|
||||
TO CHECK STATUS:
|
||||
python3 ~/natiris/agents/natiris_recovery_agent.py --status
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
"""
|
||||
return instructions
|
||||
|
||||
def create_recovery_script(self):
|
||||
"""Erstellt Recovery-Skript für automatischen Wiederanlauf"""
|
||||
script_path = self.project_root / "resume_natiris.sh"
|
||||
|
||||
script_content = """#!/bin/bash
|
||||
# Natiris Auto-Recovery Script
|
||||
# Generated by Recovery Agent
|
||||
|
||||
echo "╭────────────────────────────────────────────────────────────╮"
|
||||
echo "│ NATIRIS PROJECT RESUMER │"
|
||||
echo "╰────────────────────────────────────────────────────────────╯"
|
||||
echo ""
|
||||
|
||||
# Check if state exists
|
||||
if [ -f ~/natiris/agent_state.json ]; then
|
||||
echo "📋 Found existing state - loading progress..."
|
||||
python3 ~/natiris/agents/natiris_recovery_agent.py --resume
|
||||
else
|
||||
echo "⚠️ No state found - starting fresh..."
|
||||
python3 ~/natiris/agents/natiris_recovery_agent.py --init
|
||||
fi
|
||||
"""
|
||||
|
||||
with open(script_path, "w") as f:
|
||||
f.write(script_content)
|
||||
|
||||
# Make executable
|
||||
os.chmod(script_path, 0o755)
|
||||
log(f"Recovery script created: {script_path}")
|
||||
return str(script_path)
|
||||
|
||||
def monitor_and_track(self):
|
||||
"""Haupt-Monitoring-Loop (kann im Hintergrund laufen)"""
|
||||
log("Recovery Agent started - monitoring project...")
|
||||
|
||||
while True:
|
||||
# Speichere State regelmäßig
|
||||
self.save_state()
|
||||
|
||||
# Prüfe auf Probleme (z.B. Prozesse, Dateien)
|
||||
self.check_system_health()
|
||||
|
||||
time.sleep(30) # Alle 30 Sekunden
|
||||
|
||||
def check_system_health(self):
|
||||
"""Prüft System-Health"""
|
||||
issues = []
|
||||
|
||||
# Prüfe ComfyUI
|
||||
try:
|
||||
import requests
|
||||
resp = requests.get("http://localhost:8188/system_stats", timeout=2)
|
||||
if resp.status_code != 200:
|
||||
issues.append("ComfyUI not responding properly")
|
||||
except:
|
||||
issues.append("ComfyUI unreachable")
|
||||
|
||||
# Prüfe Ollama
|
||||
try:
|
||||
resp = requests.get("http://localhost:11434/api/tags", timeout=2)
|
||||
if resp.status_code != 200:
|
||||
issues.append("Ollama not responding")
|
||||
except:
|
||||
issues.append("Ollama unreachable")
|
||||
|
||||
if issues:
|
||||
log(f"System health issues: {', '.join(issues)}", level="WARN")
|
||||
|
||||
return len(issues) == 0
|
||||
|
||||
|
||||
def main():
|
||||
"""CLI Entry Point"""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Natiris Recovery Agent")
|
||||
parser.add_argument("--status", action="store_true", help="Show status report")
|
||||
parser.add_argument("--resume", action="store_true", help="Resume from last checkpoint")
|
||||
parser.add_argument("--init", action="store_true", help="Initialize new state")
|
||||
parser.add_argument("--complete", help="Mark task as complete")
|
||||
parser.add_argument("--phase", help="Set current phase")
|
||||
parser.add_argument("--create-recovery", action="store_true", help="Create recovery script")
|
||||
parser.add_argument("--monitor", action="store_true", help="Start monitoring mode")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
agent = NatirisRecoveryAgent()
|
||||
|
||||
if args.status:
|
||||
print(agent.get_progress_report())
|
||||
|
||||
elif args.resume:
|
||||
print(agent.get_progress_report())
|
||||
print("\n" + "="*60)
|
||||
print(agent.generate_resume_instructions())
|
||||
|
||||
elif args.init:
|
||||
agent.state = agent.get_default_state()
|
||||
agent.state["session_count"] = 1
|
||||
agent.save_state()
|
||||
log("Initialized fresh state")
|
||||
print("✓ Fresh state initialized")
|
||||
|
||||
elif args.complete:
|
||||
agent.mark_task_complete(args.complete)
|
||||
print(f"✓ Marked as complete: {args.complete}")
|
||||
|
||||
elif args.phase:
|
||||
agent.set_phase(args.phase)
|
||||
print(f"✓ Phase set to: {args.phase}")
|
||||
|
||||
elif args.create_recovery:
|
||||
script = agent.create_recovery_script()
|
||||
print(f"✓ Recovery script created: {script}")
|
||||
print(f"\nTo use: ./{script}")
|
||||
|
||||
elif args.monitor:
|
||||
agent.monitor_and_track()
|
||||
|
||||
else:
|
||||
# Default: show status
|
||||
print(agent.get_progress_report())
|
||||
print("\nUse --resume to see continuation instructions")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user