feat: TODO DB迁移+no_agent执行器+阻塞升级机制
- 创建 mofin.db → todos 表(id/title/status/priority/fix_action/retry机制) - 创建 self_todo_executor.py:no_agent脚本,纯代码逻辑 - 有fix_action→执行→验证→标记completed - 无fix_action→标记blocked→输出通知 - 失败重试3次→超限标blocked - 新blocked项首次输出后缓存不重复 - 修改 morning_health_check: - TODO写入DB取代JSON(sqlite3,无row_factory依赖) - 去重:含completed查重 - 输出阻塞TODO列表 - 替换cron:LLM cron(2h间距) → no_agent(10min间距) - 修复:deliver=origin两任务改为local - 清理:废弃todo.json退役
This commit is contained in:
@@ -134,18 +134,18 @@ def write_todos_for_issues():
|
|||||||
level = issue["level"]
|
level = issue["level"]
|
||||||
pri = todo_priority.get(level, "medium")
|
pri = todo_priority.get(level, "medium")
|
||||||
|
|
||||||
# 去重:检查是否已有相同 title
|
# 去重:检查是否已存在(含completed的也要查,避免重复加)
|
||||||
existing = conn.execute(
|
r_exist = conn.execute(
|
||||||
"SELECT id, status FROM todos WHERE title=? AND status IN ('pending','in_progress','blocked')",
|
"SELECT id, status FROM todos WHERE title=?",
|
||||||
(title,)
|
(title,)
|
||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
if existing:
|
if r_exist:
|
||||||
if existing["status"] == "blocked":
|
if r_exist[1] == "blocked":
|
||||||
# 已阻塞的重新打开
|
# 已阻塞的重新打开
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"UPDATE todos SET status='pending', priority=?, note='已重新打开', updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
"UPDATE todos SET status='pending', priority=?, note='已重新打开', updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
||||||
(pri, existing["id"])
|
(pri, r_exist[0])
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# 生成fix_action(如果可推导)
|
# 生成fix_action(如果可推导)
|
||||||
@@ -160,18 +160,15 @@ def write_todos_for_issues():
|
|||||||
new_count += 1
|
new_count += 1
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
|
||||||
|
|
||||||
if new_count > 0:
|
if new_count > 0:
|
||||||
print()
|
print()
|
||||||
print(f"📋 已加入TODO({new_count}条):")
|
print(f"📋 已加入TODO({new_count}条):")
|
||||||
# 重新查刚插入的pending记录
|
for r2 in conn.execute(
|
||||||
cur2 = conn.cursor()
|
|
||||||
for r2 in cur2.execute(
|
|
||||||
"SELECT title, priority FROM todos WHERE status='pending' AND source='health_check' "
|
"SELECT title, priority FROM todos WHERE status='pending' AND source='health_check' "
|
||||||
"ORDER BY created_at DESC LIMIT ?", (new_count,)
|
"ORDER BY created_at DESC LIMIT ?", (new_count,)
|
||||||
).fetchall():
|
).fetchall():
|
||||||
print(f" [{r2['priority']}] {r2['title'][:70]}")
|
print(f" [{r2[1]}] {r2[0][:70]}")
|
||||||
conn.close()
|
conn.close()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" TODO写入异常: {e}")
|
print(f" TODO写入异常: {e}")
|
||||||
@@ -660,6 +657,22 @@ def main():
|
|||||||
if entry["level"] in ("critical", "error"):
|
if entry["level"] in ("critical", "error"):
|
||||||
print(f" [{entry['level'].upper()}] {entry['category']}: {entry['msg']}")
|
print(f" [{entry['level'].upper()}] {entry['category']}: {entry['msg']}")
|
||||||
|
|
||||||
|
# 检查是否有阻塞的 TODO 需要知微处理
|
||||||
|
try:
|
||||||
|
conn = sqlite3.connect(str(DB_PATH))
|
||||||
|
blocked = conn.execute(
|
||||||
|
"SELECT id, title, priority, created_at FROM todos WHERE status='blocked' "
|
||||||
|
"ORDER BY CASE priority WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, created_at ASC"
|
||||||
|
).fetchall()
|
||||||
|
if blocked:
|
||||||
|
print()
|
||||||
|
print("⛔ 阻塞TODO(需知微人工处理):")
|
||||||
|
for b in blocked:
|
||||||
|
print(f" [{b[2]}] #{b[0]} {b[1][:70]} ({b[3][:10]})")
|
||||||
|
conn.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# 将异常写入 TODO 系统
|
# 将异常写入 TODO 系统
|
||||||
write_todos_for_issues()
|
write_todos_for_issues()
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ from datetime import datetime
|
|||||||
|
|
||||||
BASE = Path("/home/hmo/MoFin")
|
BASE = Path("/home/hmo/MoFin")
|
||||||
DB_PATH = BASE / "data" / "mofin.db"
|
DB_PATH = BASE / "data" / "mofin.db"
|
||||||
|
# 记录已报告过的blocked ID,避免重复推送
|
||||||
|
REPORTED_BLOCKED_PATH = Path("/home/hmo/.hermes/profiles/position-analyst/home/.cache/executor_reported_blocked.json")
|
||||||
|
|
||||||
|
|
||||||
def get_conn():
|
def get_conn():
|
||||||
@@ -76,6 +78,8 @@ def main():
|
|||||||
return
|
return
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
newly_blocked = [] # [(id, title)] 新阻塞的,需要推送给Dad/知微
|
||||||
|
|
||||||
for row in rows:
|
for row in rows:
|
||||||
todo_id = row["id"]
|
todo_id = row["id"]
|
||||||
title = row["title"]
|
title = row["title"]
|
||||||
@@ -102,6 +106,7 @@ def main():
|
|||||||
"note=?, updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
"note=?, updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
||||||
(retry_count, f"重试{retry_count}次仍失败: {output}", todo_id)
|
(retry_count, f"重试{retry_count}次仍失败: {output}", todo_id)
|
||||||
)
|
)
|
||||||
|
newly_blocked.append((todo_id, title))
|
||||||
results.append(("⛔", f"{title}: 已阻塞({output[:60]})"))
|
results.append(("⛔", f"{title}: 已阻塞({output[:60]})"))
|
||||||
else:
|
else:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
@@ -137,12 +142,31 @@ def main():
|
|||||||
"updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
"updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
||||||
(todo_id,)
|
(todo_id,)
|
||||||
)
|
)
|
||||||
|
newly_blocked.append((todo_id, title))
|
||||||
results.append(("⛔", f"{title}: 无修复命令,已阻塞"))
|
results.append(("⛔", f"{title}: 无修复命令,已阻塞"))
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
# 记录新报告过的blocked ID
|
||||||
|
try:
|
||||||
|
REPORTED_BLOCKED_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
reported = json.loads(REPORTED_BLOCKED_PATH.read_text()) if REPORTED_BLOCKED_PATH.exists() else []
|
||||||
|
# 过滤出尚未报告过的blocked项
|
||||||
|
unreported_blocked = [(tid, t) for tid, t in newly_blocked if tid not in reported]
|
||||||
|
if unreported_blocked:
|
||||||
|
# 有未报告的阻塞项 → 输出直通知微
|
||||||
|
print()
|
||||||
|
print("⛔ 需知微处理(已阻塞,无自动修复方案):")
|
||||||
|
for tid, t in unreported_blocked:
|
||||||
|
print(f" #{tid} {t[:70]}")
|
||||||
|
# 标记已报告
|
||||||
|
reported.extend([tid for tid, _ in unreported_blocked])
|
||||||
|
REPORTED_BLOCKED_PATH.write_text(json.dumps(reported[-200:], ensure_ascii=False))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
elapsed = time.time() - start
|
elapsed = time.time() - start
|
||||||
if results:
|
if results:
|
||||||
print(f"自愈执行器 | {datetime.now().strftime('%H:%M')} | {len(results)}条 ({elapsed:.0f}s)")
|
print(f"自愈执行器 | {datetime.now().strftime('%H:%M')} | {len(results)}条 ({elapsed:.0f}s)")
|
||||||
|
|||||||
Reference in New Issue
Block a user