| |
| |
| |
| |
| |
| |
| |
|
|
| import os, sys, time, json, hashlib, traceback, glob, re, requests |
| from datetime import datetime, timezone, timedelta |
| from llm_wiki import save_entry, query_context, semantic_search |
| from openai import OpenAI |
|
|
| |
| SIGNAL_FILE = "/app/latest_signals.json" |
| STATUS_FILE = "/app/hermes_status.txt" |
| ERROR_COUNT_FILE = "/app/llm_error_count.txt" |
| LAST_PROCESSED_FILE = "/app/last_processed_signal.json" |
| TASK_QUEUE_FILE = "/app/task_queue.json" |
| FOLLOW_THRESHOLD_FILE = "/app/follow_threshold.txt" |
| HALT_FILE = "/app/halt_trading.txt" |
| UNHALT_FILE = "/app/unhalt_trading.txt" |
| PENDING_ALERTS_FILE = "/app/pending_alerts.json" |
| HEALTH_LAST_ALERT_FILE = "/app/last_health_alert_level.txt" |
|
|
| |
| OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY") |
| if not OPENROUTER_API_KEY: |
| raise EnvironmentError("OPENROUTER_API_KEY must be set in Secrets.") |
|
|
| client = OpenAI( |
| base_url="https://openrouter.ai/api/v1", |
| api_key=OPENROUTER_API_KEY |
| ) |
|
|
| |
| FAST_SCAN_PRIMARY = "google/gemma-4-26b-a4b:free" |
| FAST_SCAN_FALLBACK = "google/gemma-4-31b-it-20260402:free" |
| L2_PRIMARY = "nvidia/nemotron-3-super-120b-a12b:free" |
| L2_FALLBACK = "mistralai/mistral-nemo:free" |
|
|
| |
| L3_COLLABORATOR_A = "google/gemini-2.5-flash-lite:free" |
| L3_COLLABORATOR_B = "openai/gpt-4o-mini:free" |
| L3_ARBITER = "meta-llama/llama-4-maverick:free" |
|
|
| FAST_SCAN_ROUTING = [FAST_SCAN_PRIMARY, FAST_SCAN_FALLBACK] |
| REALTIME_ROUTING = [L2_PRIMARY, L2_FALLBACK] |
| DEEP_REVIEW_COLLABORATORS = [L3_COLLABORATOR_A, L3_COLLABORATOR_B] |
| DEEP_REVIEW_ARBITER = L3_ARBITER |
|
|
| |
| def read_file(path, default=""): |
| try: |
| if os.path.exists(path): |
| with open(path, "r") as f: |
| return f.read().strip() |
| except: |
| pass |
| return default |
|
|
| def write_file(path, content): |
| try: |
| with open(path, "w") as f: |
| f.write(str(content)) |
| except: |
| pass |
|
|
| def write_status(msg): |
| try: |
| with open(STATUS_FILE, "w") as f: |
| f.write(msg + "\n") |
| except: |
| pass |
|
|
| def read_error_count(): |
| try: |
| if os.path.exists(ERROR_COUNT_FILE): |
| with open(ERROR_COUNT_FILE, "r") as f: |
| return int(f.read().strip()) |
| except: |
| pass |
| return 0 |
|
|
| def increment_error_count(error_type="unknown", detail=""): |
| count = read_error_count() + 1 |
| try: |
| with open(ERROR_COUNT_FILE, "w") as f: |
| f.write(str(count)) |
| except: |
| pass |
| try: |
| with open("/app/llm_error_types.txt", "a") as f: |
| f.write(f"[{datetime.now(timezone.utc).isoformat()}] {error_type}\n") |
| except: |
| pass |
| if detail: |
| try: |
| with open("/app/llm_error_details.txt", "a") as f: |
| f.write(f"[{datetime.now(timezone.utc).isoformat()}] {error_type}: {detail[:100]}\n") |
| except: |
| pass |
|
|
| def reset_error_count(): |
| try: |
| with open(ERROR_COUNT_FILE, "w") as f: |
| f.write("0") |
| with open("/app/llm_error_types.txt", "w") as f: |
| f.write("") |
| with open("/app/llm_error_details.txt", "w") as f: |
| f.write("") |
| except: |
| pass |
|
|
| def read_signals(): |
| try: |
| if os.path.exists(SIGNAL_FILE): |
| with open(SIGNAL_FILE, "r") as f: |
| return json.load(f) |
| except: |
| pass |
| return [] |
|
|
| def clear_signals(): |
| try: |
| with open(SIGNAL_FILE, "w") as f: |
| json.dump([], f) |
| except: |
| pass |
|
|
| def get_follow_threshold(): |
| try: |
| if os.path.exists(FOLLOW_THRESHOLD_FILE): |
| with open(FOLLOW_THRESHOLD_FILE, "r") as f: |
| return float(f.read().strip()) |
| except: |
| pass |
| return 0.6 |
|
|
| def is_halted(): |
| try: |
| if os.path.exists(HALT_FILE): |
| return True |
| if os.path.exists("/app/capital_state.json"): |
| with open("/app/capital_state.json", "r") as f: |
| state = json.load(f) |
| if state.get("halted", False): |
| return True |
| except: |
| pass |
| return False |
|
|
| |
| def send_telegram_alert(text: str): |
| token = os.getenv("TELEGRAM_BOT_TOKEN") |
| chat_id = os.getenv("TELEGRAM_CHAT_ID") |
| if not token or not chat_id: |
| return False |
| url = f"https://api.telegram.org/bot{token}/sendMessage" |
| try: |
| resp = requests.post(url, json={"chat_id": chat_id, "text": text}, timeout=10) |
| return resp.status_code == 200 |
| except: |
| return False |
|
|
| def add_pending_alert(alert_text): |
| alerts = [] |
| try: |
| if os.path.exists(PENDING_ALERTS_FILE): |
| with open(PENDING_ALERTS_FILE, "r") as f: |
| alerts = json.load(f) |
| except: |
| pass |
| alerts.append({"text": alert_text, "timestamp": time.time()}) |
| try: |
| with open(PENDING_ALERTS_FILE, "w") as f: |
| json.dump(alerts, f) |
| except: |
| pass |
|
|
| def flush_pending_alerts(): |
| if not os.path.exists(PENDING_ALERTS_FILE): |
| return |
| try: |
| with open(PENDING_ALERTS_FILE, "r") as f: |
| alerts = json.load(f) |
| except: |
| return |
| remaining = [] |
| for alert in alerts: |
| if time.time() - alert["timestamp"] > 86400: |
| continue |
| if not send_telegram_alert(alert["text"]): |
| remaining.append(alert) |
| try: |
| if remaining: |
| with open(PENDING_ALERTS_FILE, "w") as f: |
| json.dump(remaining, f) |
| else: |
| if os.path.exists(PENDING_ALERTS_FILE): |
| os.remove(PENDING_ALERTS_FILE) |
| except: |
| pass |
|
|
| |
| def get_market_sentiment(): |
| try: |
| resp = requests.get("https://data-api.polymarket.com/markets?limit=50", timeout=10) |
| if resp.status_code == 200: |
| data = resp.json() |
| if isinstance(data, list) and data: |
| total = len(data) |
| bullish = sum(1 for m in data if float(m.get("outcomePrices", [0, 0])[0]) > 0.7) |
| sentiment = (bullish / total - 0.5) * 2 |
| return round(sentiment, 2) |
| except: |
| pass |
| return 0.0 |
|
|
| |
| def call_llm_with_routing(prompt: str, routing: list, task_label: str = "", max_tokens: int = 200) -> str: |
| for model in routing: |
| try: |
| response = client.chat.completions.create( |
| model=model, |
| messages=[{"role": "user", "content": prompt}], |
| temperature=0.3, |
| max_tokens=max_tokens |
| ) |
| |
| if response and response.choices and len(response.choices) > 0: |
| result = response.choices[0].message.content |
| if result: |
| result = result.strip() |
| print(f"[Hermes] {task_label} β Model {model} succeeded.", flush=True) |
| return result |
| |
| print(f"[Hermes] {task_label} β Model {model} returned empty/None, trying next.", flush=True) |
| except Exception as e: |
| error_msg = str(e) |
| if "429" in error_msg: |
| increment_error_count("rate_limit", error_msg) |
| elif "502" in error_msg: |
| increment_error_count("model_down", error_msg) |
| elif "401" in error_msg: |
| increment_error_count("auth_error", error_msg) |
| elif "timeout" in error_msg.lower(): |
| increment_error_count("network", error_msg) |
| else: |
| increment_error_count("other", error_msg) |
| print(f"[Hermes] {task_label} β Model {model} failed: {e}", flush=True) |
| continue |
| print(f"[Hermes] {task_label} β All models failed.", flush=True) |
| return "" |
|
|
| |
| def compute_health_score(): |
| polyhub_status = read_file("/app/polyhub_status.txt", "unknown") |
| hermes_status = read_file("/app/hermes_status.txt", "unknown") |
| balance_status = read_file("/app/balance_status.txt", "unknown") |
| backup_status = read_file("/app/backup_status.txt", "disabled") |
| halted = False |
| try: |
| if os.path.exists("/app/capital_state.json"): |
| with open("/app/capital_state.json") as f: |
| state = json.load(f) |
| halted = state.get("halted", False) |
| except: |
| pass |
| score = 100 |
| if "running" not in polyhub_status: score -= 30 |
| if "running" not in hermes_status: score -= 30 |
| if "running" not in balance_status: score -= 20 |
| if halted: score -= 20 |
| if backup_status == "failed": score -= 10 |
| return score, { |
| "polyhub": polyhub_status, "hermes": hermes_status, |
| "balance": balance_status, "backup": backup_status, "halted": halted |
| } |
|
|
| def health_monitor(): |
| score, details = compute_health_score() |
| last_level = read_file(HEALTH_LAST_ALERT_FILE, "") |
| if score >= 70: current_level = "normal" |
| elif score >= 40: current_level = "warning" |
| else: current_level = "critical" |
| if current_level != last_level: |
| if current_level == "warning": |
| msg = f"β οΈ Health Score dropped to {score}/100\n\n{json.dumps(details, indent=2)}" |
| elif current_level == "critical": |
| msg = f"π¨ CRITICAL Health Score: {score}/100\n\n{json.dumps(details, indent=2)}" |
| else: |
| msg = f"β
Health Score restored to {score}/100" |
| if send_telegram_alert(msg): |
| write_file(HEALTH_LAST_ALERT_FILE, current_level) |
| else: |
| add_pending_alert(msg) |
| write_file(HEALTH_LAST_ALERT_FILE, current_level) |
| return score, details |
|
|
| |
| def consensus_analyze(signal, context): |
| prompt = f"""You are a Polymarket trading assistant. A signal was detected: |
| - Market: {signal.get('market_slug')} |
| - Action: {signal.get('action')} |
| - Confidence score: {signal.get('confidence')} |
| - Amount: ${signal.get('amount_usd')} |
| Relevant past knowledge: {context} |
| Market sentiment: {get_market_sentiment()} |
| Current follow threshold: {get_follow_threshold()} |
| |
| Should we follow this signal? Reply with "FOLLOW" or "IGNORE" and briefly explain.""" |
| return _dual_collaborator_decision(prompt, "Consensus") |
|
|
| def _dual_collaborator_decision(prompt: str, task_label: str) -> str: |
| """Ask both L3 collaborators; if they disagree, ask the arbiter.""" |
| decision_a = call_llm_with_routing(prompt, [L3_COLLABORATOR_A], f"{task_label}-A", max_tokens=150) |
| decision_b = call_llm_with_routing(prompt, [L3_COLLABORATOR_B], f"{task_label}-B", max_tokens=150) |
| if not decision_a or not decision_b: |
| fallback = call_llm_with_routing(prompt, [L3_ARBITER], f"{task_label}-Arbiter", max_tokens=150) |
| return fallback if fallback else "IGNORE (model error)" |
| a_follow = "FOLLOW" in decision_a.upper() |
| b_follow = "FOLLOW" in decision_b.upper() |
| if a_follow == b_follow: |
| return decision_a if a_follow else decision_b |
| arbiter_prompt = f"""Two models disagreed on a trading signal. |
| |
| Model A says: {decision_a} |
| Model B says: {decision_b} |
| |
| Original prompt: {prompt} |
| |
| As the arbiter, which decision (FOLLOW or IGNORE) is more appropriate? Reply with "FOLLOW" or "IGNORE" and briefly explain.""" |
| arbiter_decision = call_llm_with_routing(arbiter_prompt, [L3_ARBITER], f"{task_label}-Arbiter", max_tokens=150) |
| if not arbiter_decision: |
| return "IGNORE (arbiter failed)" |
| return arbiter_decision |
|
|
| |
| def analyze_signal(signal: dict, context: str) -> str: |
| confidence = signal.get("confidence", 0) |
| threshold = get_follow_threshold() |
| high_confidence = False |
| if confidence >= 0.8: |
| try: |
| if os.path.exists("/app/cluster_results.json"): |
| with open("/app/cluster_results.json", "r") as f: |
| cluster_data = json.load(f) |
| followed = cluster_data.get("followed_wallets", []) |
| if len(followed) >= 2: |
| high_confidence = True |
| except: |
| pass |
| if high_confidence: |
| return consensus_analyze(signal, context) |
|
|
| prompt = f"""You are a Polymarket trading assistant. A signal was detected: |
| - Wallet: {signal.get('wallet_address')} |
| - Market: {signal.get('market_slug')} |
| - Action: {signal.get('action')} |
| - Confidence score: {confidence} |
| - Amount: ${signal.get('amount_usd')} |
| - Analysis mode: standard |
| - Market sentiment: {get_market_sentiment()} |
| - Current follow threshold: {threshold} |
| |
| Relevant past knowledge from our wiki: |
| {context if context else 'No historical data found.'} |
| |
| Given the above, should we follow this signal? Reply with "FOLLOW" or "IGNORE" and briefly explain. |
| """ |
| decision = call_llm_with_routing(prompt, REALTIME_ROUTING, f"Signal-{signal.get('market_slug', 'unknown')[:30]}") |
| if not decision: |
| return "IGNORE (LLM error)" |
| if "FOLLOW" not in decision and "IGNORE" not in decision: |
| return f"IGNORE (ambiguous: {decision[:80]})" |
| return decision |
|
|
| |
| def process_task_queue(): |
| tasks = [] |
| try: |
| if os.path.exists(TASK_QUEUE_FILE): |
| with open(TASK_QUEUE_FILE, "r") as f: |
| tasks = json.load(f) |
| except: |
| return |
| if not tasks: |
| return |
| for task in tasks[:5]: |
| cmd = task.get("command", "") |
| print(f"[Hermes] Processing task: {cmd}", flush=True) |
| if cmd.startswith("analyze"): |
| market = cmd.split(" ", 1)[1] if " " in cmd else "btc-updown-5m-1779771300" |
| prompt = f"Analyze the following Polymarket market briefly (max 150 words): {market}. Include current pricing, liquidity, and any relevant historical patterns from the wiki." |
| result = call_llm_with_routing(prompt, DEEP_REVIEW_COLLABORATORS, "Task-Analyze", max_tokens=250) |
| if result: |
| save_entry(topic=f"Task-Analysis-{market[:30]}", content=result, tags=["task", "analysis"]) |
| elif cmd.startswith("report"): |
| with open("/app/force_report.txt", "w") as f: |
| f.write("1") |
| elif cmd.startswith("threshold"): |
| try: |
| val = float(cmd.split(" ")[1]) |
| with open(FOLLOW_THRESHOLD_FILE, "w") as f: |
| f.write(str(val)) |
| print(f"[Hermes] Threshold updated to {val}", flush=True) |
| except: |
| pass |
| task["status"] = "done" |
| task["completed_at"] = datetime.now(timezone.utc).isoformat() |
| tasks = [t for t in tasks if t.get("status") != "done"] |
| try: |
| with open(TASK_QUEUE_FILE, "w") as f: |
| json.dump(tasks, f) |
| except: |
| pass |
|
|
| |
| def auto_adjust_threshold(): |
| wiki_dir = "/app/wiki" |
| signals = [] |
| try: |
| for fp in sorted(glob.glob(os.path.join(wiki_dir, "*.md")), reverse=True)[:200]: |
| with open(fp, "r") as f: |
| content = f.read() |
| if "FOLLOW" in content or "IGNORE" in content: |
| signals.append(content) |
| except: |
| return |
| if len(signals) < 20: |
| return |
| prompt = f"""You are analyzing historical trading signals. The last {len(signals)} signal analyses are summarized below (excerpts): |
| {chr(10).join(signals[:10])} |
| Based on these patterns, what confidence threshold (between 0.5 and 0.9) would have maximized profit while minimizing losing trades? |
| Reply with just a number between 0.5 and 0.9 and a 1βsentence explanation. |
| """ |
| result = call_llm_with_routing(prompt, DEEP_REVIEW_COLLABORATORS, "AutoThreshold", max_tokens=100) |
| if result: |
| try: |
| nums = re.findall(r"0\.\d+", result) |
| if nums: |
| new_threshold = float(nums[0]) |
| new_threshold = max(0.5, min(0.9, new_threshold)) |
| with open(FOLLOW_THRESHOLD_FILE, "w") as f: |
| f.write(str(new_threshold)) |
| print(f"[Hermes] Autoβadjusted threshold to {new_threshold}", flush=True) |
| save_entry(topic="AutoThreshold-Adjustment", content=f"New threshold: {new_threshold}\nReason: {result}", tags=["auto", "threshold"]) |
| except: |
| pass |
|
|
| |
| def auto_adjust_threshold_from_performance(): |
| try: |
| if not os.path.exists("/app/virtual_positions.json"): |
| return |
| with open("/app/virtual_positions.json", "r") as f: |
| positions = json.load(f) |
| closed = [p for p in positions if p.get("status") == "closed"] |
| if len(closed) < 5: |
| return |
| recent = sorted(closed, key=lambda p: p.get("exit_time", ""), reverse=True)[:10] |
| wins = [p for p in recent if p.get("result") == "win"] |
| win_rate = len(wins) / len(recent) |
| threshold = get_follow_threshold() |
| new_threshold = threshold |
| if win_rate >= 0.6 and threshold > 0.5: |
| new_threshold = round(threshold - 0.02, 2) |
| new_threshold = max(0.5, new_threshold) |
| elif win_rate <= 0.4 and threshold < 0.8: |
| new_threshold = round(threshold + 0.02, 2) |
| new_threshold = min(0.8, new_threshold) |
| if new_threshold != threshold: |
| with open(FOLLOW_THRESHOLD_FILE, "w") as f: |
| f.write(str(new_threshold)) |
| print(f"[Hermes] Performanceβbased threshold: {threshold} β {new_threshold} (win rate {win_rate:.0%})", flush=True) |
| save_entry( |
| topic="AutoThreshold-Performance", |
| content=f"Threshold changed from {threshold} to {new_threshold} (last 10 win rate {win_rate:.0%})", |
| tags=["auto", "threshold", "performance"] |
| ) |
| except Exception as e: |
| print(f"[Hermes] Failed performance threshold adjustment: {e}", flush=True) |
|
|
| |
| def daily_reflection(): |
| print("[Hermes] Starting daily reflection...", flush=True) |
| try: |
| trades = [] |
| if os.path.exists("/app/virtual_positions.json"): |
| with open("/app/virtual_positions.json", "r") as f: |
| positions = json.load(f) |
| cutoff = datetime.now(timezone.utc) - timedelta(days=7) |
| for p in positions: |
| if p.get("status") == "closed": |
| try: |
| exit_time = datetime.fromisoformat(p.get("exit_time", "")) |
| if exit_time > cutoff: |
| trades.append({ |
| "market": p.get("market",""), |
| "action": p.get("action",""), |
| "result": p.get("result",""), |
| "pnl": p.get("pnl",0) |
| }) |
| except: |
| pass |
| flags_closed = [] |
| if os.path.exists("/app/flags.json"): |
| with open("/app/flags.json", "r") as f: |
| flags = json.load(f) |
| for fl in flags: |
| if fl.get("status") == "closed": |
| try: |
| closed_at = datetime.fromisoformat(fl.get("closed_at", "")) |
| if closed_at > cutoff: |
| flags_closed.append({ |
| "description": fl.get("description",""), |
| "result": fl.get("result","") |
| }) |
| except: |
| pass |
| notes = [] |
| try: |
| with open("/app/notes.txt", "r") as f: |
| lines = f.readlines() |
| recent_lines = [l.strip() for l in lines if l.strip()] |
| notes = recent_lines[-10:] |
| except: |
| pass |
| prompt = f"""You are a selfβreflection module for an automated trading system. |
| Below is a summary of the last 7 days: |
| |
| **Closed Virtual Trades:** {json.dumps(trades, indent=2)} |
| **Closed Flags:** {json.dumps(flags_closed, indent=2)} |
| **Recent Macro Notes:** {json.dumps(notes, indent=2)} |
| |
| Please analyze: |
| 1. Which types of signals performed well? Which performed poorly? |
| 2. Are there patterns in the flags accuracy vs. market type? |
| 3. How well do the macro notes align with actual outcomes? |
| 4. What concrete adjustments should the trading agent make (e.g., focus on certain sports/markets, adjust confidence threshold)? |
| Reply in concise bullet points. Maximum 200 words. |
| """ |
| reflection = call_llm_with_routing(prompt, DEEP_REVIEW_COLLABORATORS, "DailyReflection", max_tokens=300) |
| if reflection: |
| save_entry(topic="Daily-Reflection", content=reflection, tags=["reflection", "daily"]) |
| with open("/app/latest_reflection.txt", "w") as f: |
| f.write(reflection) |
| msg = f"π§ Daily Reflection\n\n{reflection[:1500]}" |
| send_telegram_alert(msg) |
| print("[Hermes] Daily reflection completed.", flush=True) |
| else: |
| print("[Hermes] Daily reflection failed (no LLM response).", flush=True) |
| except Exception as e: |
| print(f"[Hermes] Daily reflection error: {e}", flush=True) |
|
|
| |
| decision_cache = {} |
|
|
| def process_signals(): |
| signals = read_signals() |
| print(f"[Hermes] Woke up. Signals in queue: {len(signals)}", flush=True) |
| if not signals: |
| return |
| if is_halted(): |
| print("[Hermes] Trading halted β skipping signal processing.", flush=True) |
| clear_signals() |
| return |
|
|
| reflection_text = read_file("/app/latest_reflection.txt", "") |
| recent_notes_text = "" |
| try: |
| with open("/app/notes.txt", "r") as f: |
| lines = [line.strip() for line in f.readlines() if line.strip()] |
| if lines: |
| recent_notes_text = "Recent macro notes:\n" + "\n".join(lines[-5:]) |
| except: |
| pass |
|
|
| for signal in signals: |
| keywords = signal["market_slug"].split("-") |
| try: |
| context = semantic_search(signal.get("market_slug", ""), top_k=3) |
| except: |
| context = query_context(keywords) |
|
|
| enriched_context = context |
| if reflection_text: |
| enriched_context = f"[Latest Reflection]\n{reflection_text}\n\n{enriched_context}" |
| if recent_notes_text: |
| enriched_context = f"{recent_notes_text}\n\n{enriched_context}" |
|
|
| sig_str = json.dumps(signal, sort_keys=True) |
| sig_hash = hashlib.md5(sig_str.encode()).hexdigest() |
| now = time.time() |
|
|
| if sig_hash in decision_cache and (now - decision_cache[sig_hash][1]) < 3600: |
| print(f"[Hermes] Using cached decision for {signal.get('market_slug')}", flush=True) |
| decision = decision_cache[sig_hash][0] |
| else: |
| print(f"[Hermes] Processing signal for {signal.get('market_slug')}...", flush=True) |
| decision = analyze_signal(signal, enriched_context) |
| decision_cache[sig_hash] = (decision, now) |
|
|
| print(f"[Hermes] Decision for {signal['market_slug']}: {decision}", flush=True) |
| summary = f"Signal: {json.dumps(signal)}\nDecision: {decision}" |
| save_entry(topic=f"Signal-{signal['market_slug']}", content=summary, tags=keywords) |
|
|
| if signals: |
| try: |
| signal_with_time = signals[-1].copy() |
| signal_with_time["processed_at"] = datetime.now(timezone.utc).isoformat() |
| signal_with_time["decision"] = decision_cache.get(hashlib.md5(json.dumps(signals[-1], sort_keys=True).encode()).hexdigest(), ("", 0))[0] |
| with open(LAST_PROCESSED_FILE, "w") as f: |
| json.dump(signal_with_time, f) |
| except: |
| pass |
| clear_signals() |
|
|
| |
| def check_cron_jobs(): |
| now = datetime.now(timezone.utc) |
| if now.hour in (0, 6, 12, 18) and now.minute == 0: |
| print(f"[Hermes] Cron: Auto market analysis at {now.hour}:00 UTC", flush=True) |
| prompt = "Analyze the 3 most active Polymarket markets right now. For each, provide current probability, liquidity, and a brief assessment." |
| result = call_llm_with_routing(prompt, DEEP_REVIEW_COLLABORATORS, "Cron-Analyze", max_tokens=300) |
| if result: |
| save_entry(topic=f"AutoAnalysis-{now.strftime('%Y-%m-%d-%H')}", content=result, tags=["auto", "analysis"]) |
|
|
| if now.weekday() == 0 and now.hour == 0 and now.minute == 0: |
| print("[Hermes] Cron: Weekly full review", flush=True) |
| auto_adjust_threshold() |
|
|
| if now.hour == 0 and now.minute == 0 and now.second < 5: |
| auto_adjust_threshold_from_performance() |
|
|
| if now.hour == 0 and now.minute == 5 and now.second < 5: |
| daily_reflection() |
|
|
| if now.minute % 5 == 0 and now.second < 5: |
| health_monitor() |
|
|
| |
| def agent_loop(): |
| try: |
| print("[Hermes] Multi-tier hybrid agent loop starting...", flush=True) |
| write_status("running") |
| last_reset_day = None |
| last_cron_check = 0 |
| while True: |
| now_utc = datetime.now(timezone.utc) |
| if now_utc.hour == 0 and now_utc.minute == 0 and now_utc.day != last_reset_day: |
| reset_error_count() |
| last_reset_day = now_utc.day |
| print("[Hermes] Daily LLM error counter reset.", flush=True) |
| current_time = time.time() |
| if current_time - last_cron_check >= 60: |
| check_cron_jobs() |
| last_cron_check = current_time |
| process_task_queue() |
| flush_pending_alerts() |
| process_signals() |
| time.sleep(60) |
| except Exception as e: |
| error_msg = f"[Hermes] CRASH: {e}\n{traceback.format_exc()}" |
| print(error_msg, flush=True) |
| write_status(f"crashed: {e}") |
|
|
| if __name__ == "__main__": |
| agent_loop() |