Spaces:
Running
Running
Upload core/strategy.py with huggingface_hub
Browse files- core/strategy.py +160 -0
core/strategy.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Strategy Reflector — Self-Improvement Engine
|
| 3 |
+
==============================================
|
| 4 |
+
Analyzes agent performance and generates improvement strategies.
|
| 5 |
+
"""
|
| 6 |
+
import json
|
| 7 |
+
import logging
|
| 8 |
+
from datetime import datetime, timezone
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
from typing import Optional
|
| 11 |
+
|
| 12 |
+
logger = logging.getLogger("openclaw.strategy")
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class StrategyReflector:
|
| 16 |
+
"""Analyzes performance and suggests improvements."""
|
| 17 |
+
|
| 18 |
+
def __init__(self, state_dir: str = "state"):
|
| 19 |
+
self.state_dir = Path(state_dir)
|
| 20 |
+
|
| 21 |
+
def analyze(self) -> dict:
|
| 22 |
+
"""Run full analysis of agent performance."""
|
| 23 |
+
metrics = self._gather_metrics()
|
| 24 |
+
insights = self._derive_insights(metrics)
|
| 25 |
+
strategy = self._generate_strategy(insights)
|
| 26 |
+
|
| 27 |
+
report = {
|
| 28 |
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
| 29 |
+
"metrics": metrics,
|
| 30 |
+
"insights": insights,
|
| 31 |
+
"strategy": strategy,
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
# Save report
|
| 35 |
+
self.state_dir.mkdir(parents=True, exist_ok=True)
|
| 36 |
+
with open(self.state_dir / "strategy_report.json", "w") as f:
|
| 37 |
+
json.dump(report, f, indent=2)
|
| 38 |
+
|
| 39 |
+
return report
|
| 40 |
+
|
| 41 |
+
def _gather_metrics(self) -> dict:
|
| 42 |
+
"""Gather all available metrics."""
|
| 43 |
+
metrics = {
|
| 44 |
+
"total_cycles": 0,
|
| 45 |
+
"total_posts": 0,
|
| 46 |
+
"total_engagements": 0,
|
| 47 |
+
"papers_shared": 0,
|
| 48 |
+
"errors": 0,
|
| 49 |
+
"uptime_hours": 0,
|
| 50 |
+
"post_frequency": 0,
|
| 51 |
+
"services_available": 0,
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
# Load from agent state
|
| 55 |
+
state_file = self.state_dir / "agent_state.json"
|
| 56 |
+
if state_file.exists():
|
| 57 |
+
try:
|
| 58 |
+
with open(state_file) as f:
|
| 59 |
+
state = json.load(f)
|
| 60 |
+
metrics["total_cycles"] = state.get("cycle_count", 0)
|
| 61 |
+
metrics["total_posts"] = state.get("posts_created", 0)
|
| 62 |
+
metrics["total_engagements"] = state.get("engagement_count", 0)
|
| 63 |
+
metrics["papers_shared"] = len(state.get("posted_paper_ids", []))
|
| 64 |
+
metrics["errors"] = len(state.get("errors", []))
|
| 65 |
+
|
| 66 |
+
# Calculate uptime
|
| 67 |
+
started = state.get("started_at", "")
|
| 68 |
+
if started:
|
| 69 |
+
try:
|
| 70 |
+
start_dt = datetime.fromisoformat(started)
|
| 71 |
+
if start_dt.tzinfo is None:
|
| 72 |
+
start_dt = start_dt.replace(tzinfo=timezone.utc)
|
| 73 |
+
delta = datetime.now(timezone.utc) - start_dt
|
| 74 |
+
metrics["uptime_hours"] = round(delta.total_seconds() / 3600, 1)
|
| 75 |
+
except Exception:
|
| 76 |
+
pass
|
| 77 |
+
except Exception:
|
| 78 |
+
pass
|
| 79 |
+
|
| 80 |
+
# Load from post history
|
| 81 |
+
history_file = self.state_dir / "post_history.json"
|
| 82 |
+
if history_file.exists():
|
| 83 |
+
try:
|
| 84 |
+
with open(history_file) as f:
|
| 85 |
+
history = json.load(f)
|
| 86 |
+
if history and metrics["uptime_hours"] > 0:
|
| 87 |
+
metrics["post_frequency"] = round(
|
| 88 |
+
len(history) / max(metrics["uptime_hours"] / 24, 1), 2
|
| 89 |
+
)
|
| 90 |
+
except Exception:
|
| 91 |
+
pass
|
| 92 |
+
|
| 93 |
+
return metrics
|
| 94 |
+
|
| 95 |
+
def _derive_insights(self, metrics: dict) -> list[str]:
|
| 96 |
+
"""Derive actionable insights from metrics."""
|
| 97 |
+
insights = []
|
| 98 |
+
|
| 99 |
+
if metrics["total_cycles"] == 0:
|
| 100 |
+
insights.append("Agent has not completed any cycles yet. First run pending.")
|
| 101 |
+
return insights
|
| 102 |
+
|
| 103 |
+
# Post frequency analysis
|
| 104 |
+
if metrics["total_posts"] == 0:
|
| 105 |
+
insights.append("CRITICAL: No posts created. Check Moltbook API connection and account status.")
|
| 106 |
+
elif metrics["post_frequency"] < 2:
|
| 107 |
+
insights.append("Low post frequency. Consider increasing research post rate or adding more platforms.")
|
| 108 |
+
elif metrics["post_frequency"] > 10:
|
| 109 |
+
insights.append("High post frequency. Risk of appearing spammy. Consider quality over quantity.")
|
| 110 |
+
|
| 111 |
+
# Engagement analysis
|
| 112 |
+
if metrics["total_engagements"] == 0 and metrics["total_cycles"] > 5:
|
| 113 |
+
insights.append("No engagements despite multiple cycles. Review engagement strategy and keyword matching.")
|
| 114 |
+
|
| 115 |
+
# Error rate
|
| 116 |
+
if metrics["errors"] > metrics["total_cycles"] * 0.3:
|
| 117 |
+
insights.append(f"High error rate ({metrics['errors']}/{metrics['total_cycles']}). Investigate API failures.")
|
| 118 |
+
|
| 119 |
+
# Paper sharing
|
| 120 |
+
if metrics["papers_shared"] < 3 and metrics["total_cycles"] > 10:
|
| 121 |
+
insights.append("Few papers shared. Ensure ArXiv fetcher is working and paper cache is populated.")
|
| 122 |
+
|
| 123 |
+
# Platform diversity
|
| 124 |
+
insights.append("Currently using Moltbook only. Consider adding: Chirper.ai, Reddit, Twitter for wider reach.")
|
| 125 |
+
|
| 126 |
+
if not insights:
|
| 127 |
+
insights.append("Agent operating within normal parameters.")
|
| 128 |
+
|
| 129 |
+
return insights
|
| 130 |
+
|
| 131 |
+
def _generate_strategy(self, insights: list[str]) -> dict:
|
| 132 |
+
"""Generate improvement strategy from insights."""
|
| 133 |
+
actions = []
|
| 134 |
+
priorities = []
|
| 135 |
+
|
| 136 |
+
for insight in insights:
|
| 137 |
+
if "CRITICAL" in insight:
|
| 138 |
+
priorities.append("HIGH: " + insight)
|
| 139 |
+
actions.append("Diagnose and fix API connection immediately")
|
| 140 |
+
elif "No posts" in insight or "No engagements" in insight:
|
| 141 |
+
priorities.append("MEDIUM: " + insight)
|
| 142 |
+
actions.append("Review API keys and platform access")
|
| 143 |
+
elif "platform" in insight.lower() or "wider reach" in insight.lower():
|
| 144 |
+
actions.append("Implement multi-platform support (Chirper.ai, Reddit)")
|
| 145 |
+
elif "error rate" in insight.lower():
|
| 146 |
+
actions.append("Add retry logic and circuit breaker patterns")
|
| 147 |
+
|
| 148 |
+
# Default strategic actions
|
| 149 |
+
actions.extend([
|
| 150 |
+
"Scan ArXiv weekly for papers citing our work",
|
| 151 |
+
"Track which topics generate most engagement",
|
| 152 |
+
"Build keyword database from successful interactions",
|
| 153 |
+
"Monitor new AI agent platforms for early adoption",
|
| 154 |
+
])
|
| 155 |
+
|
| 156 |
+
return {
|
| 157 |
+
"priorities": priorities,
|
| 158 |
+
"actions": actions[:10],
|
| 159 |
+
"next_review": "24 hours",
|
| 160 |
+
}
|