Files
MoFin/scripts/self_todo_executor.py
T
知微 11254c8834 fix: 取消blocked,改为needs_llm升级机制
- executor重试耗尽→needs_llm(需知微介入),非blocked
- health check报告尾段展示needs_llm项+失败原因
- derive_fix_action覆盖全部已知场景(cron errors/delivery等)
- TODO创建时注明"无法当场修复原因"
- 每个TODO必有fix_action,没有的不创建TODOs直接在报告列出
2026-06-24 21:26:23 +08:00

117 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""self_todo_executor.py — TODO自动执行器 (no_agent模式)
每10分钟轮询mofin.db中todos表的pending任务,执行fix_action命令。
没有"blocked"状态。能修就修,修不了留着等明天体检再说。
纯代码逻辑,不调LLM。
"""
import json, os, sqlite3, subprocess, sys, time
from pathlib import Path
from datetime import datetime
BASE = Path("/home/hmo/MoFin")
DB_PATH = BASE / "data" / "mofin.db"
def get_conn():
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
return conn
def execute_fix(fix_action):
"""执行修复命令,返回 (ok, output)"""
if not fix_action:
return False, "无修复命令"
try:
r = subprocess.run(
fix_action,
shell=True, capture_output=True, text=True, timeout=60
)
if r.returncode == 0:
return True, r.stdout.strip()[:300] or "ok"
else:
return False, f"exit={r.returncode}: {r.stderr.strip()[:300]}"
except subprocess.TimeoutExpired:
return False, "执行超时(60s)"
except Exception as e:
return False, str(e)[:200]
def main():
start = time.time()
conn = get_conn()
rows = conn.execute(
"SELECT id, title, fix_action, retry_count, max_retries FROM todos "
"WHERE status='pending' ORDER BY "
"CASE priority WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, "
"created_at ASC LIMIT 5"
).fetchall()
if not rows:
conn.close()
print("[SILENT] 无待处理TODO")
return
results = []
for row in rows:
todo_id = row["id"]
title = row["title"]
fix_action = row["fix_action"]
retry_count = row["retry_count"]
max_retries = row["max_retries"]
if not fix_action:
# 没有fix_action就不应该创建这个TODO,跳过
conn.execute(
"UPDATE todos SET status='completed', note='无修复命令,跳过', "
"updated_at=CURRENT_TIMESTAMP WHERE id=?", (todo_id,))
results.append(("⏭️", f"{title}: 无修复命令"))
conn.commit()
continue
# 执行
conn.execute(
"UPDATE todos SET status='in_progress', updated_at=CURRENT_TIMESTAMP WHERE id=?",
(todo_id,))
conn.commit()
ok, output = execute_fix(fix_action)
if ok:
conn.execute(
"UPDATE todos SET status='completed', note=?, "
"updated_at=CURRENT_TIMESTAMP WHERE id=?",
(f"已修复: {output[:200]}", todo_id))
results.append(("", f"{title}: 已修复"))
else:
retry_count += 1
if retry_count >= max_retries:
# 重试用完,超出能力范围→标记需LLM处理
conn.execute(
"UPDATE todos SET status='needs_llm', retry_count=?, "
"note=?, updated_at=CURRENT_TIMESTAMP WHERE id=?",
(retry_count, f"尝试{retry_count}次仍失败: {output[:150]}", todo_id))
results.append(("🔶", f"{title}: 需知微介入(重试{retry_count}次失败)"))
else:
conn.execute(
"UPDATE todos SET status='pending', retry_count=?, "
"note=?, updated_at=CURRENT_TIMESTAMP WHERE id=?",
(retry_count, f"{retry_count}次失败: {output[:100]}", todo_id))
results.append(("🔄", f"{title}: 重试{retry_count}/{max_retries}"))
conn.commit()
conn.close()
elapsed = time.time() - start
if results:
print(f"自愈执行器 | {datetime.now().strftime('%H:%M')} | {len(results)}条 ({elapsed:.0f}s)")
for icon, msg in results:
print(f" {icon} {msg}")
if __name__ == "__main__":
main()