migrate_hermes: schema-tolerant sessions (у Риты нет last_activity_at), REPO_ROOT fix (импорт стора из scripts/), живые чаты раньше крона в истории

This commit is contained in:
Simbiot Harness 2026-10-02 22:24:17 +00:00
parent 61858a408b
commit d7ee7d1fcb

View file

@ -41,6 +41,9 @@ import sys
import time import time
from datetime import datetime, timezone from datetime import datetime, timezone
# корень репо Simbiot (файл лежит в scripts/): импорт стора + OUT-пакет
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MAX_HISTORY_SESSIONS = 40 # сколько последних сессий с диалогом переносим MAX_HISTORY_SESSIONS = 40 # сколько последних сессий с диалогом переносим
MAX_HISTORY_MSGS_PER_SESSION = 40 MAX_HISTORY_MSGS_PER_SESSION = 40
MAX_TOTAL_HISTORY_MSGS = 150 MAX_TOTAL_HISTORY_MSGS = 150
@ -135,23 +138,47 @@ def extract_history(hermes_dir: str, out_dir: str) -> dict:
return res return res
db = sqlite3.connect(f"file:{state}?mode=ro", uri=True) db = sqlite3.connect(f"file:{state}?mode=ro", uri=True)
db.row_factory = sqlite3.Row db.row_factory = sqlite3.Row
sessions = db.execute(""" # схемы Гермеса различаются по версиям (t-261001124130: у Риты нет
# last_activity_at) — толерантный ORDER BY
scols = {r[1] for r in db.execute("PRAGMA table_info(sessions)")}
if "last_activity_at" in scols:
order_expr = "COALESCE(s.last_activity_at, s.started_at)"
last_expr = "s.last_activity_at"
else:
order_expr = "s.started_at"
last_expr = "s.started_at"
# два прохода (t-261001124130): сначала ЖИВЫЕ чаты (telegram/matrix/cli/
# subagent) — крон-сессии (watchdog-пинги, отчёты) шумом съедали весь кап;
# крон берём только в остаток лимита
sessions = db.execute(f"""
SELECT s.id, s.source, s.chat_type, s.display_name, s.title, SELECT s.id, s.source, s.chat_type, s.display_name, s.title,
s.started_at, s.last_activity_at, COUNT(m.id) n s.started_at, {last_expr} AS last_at, COUNT(m.id) n
FROM sessions s JOIN messages m ON m.session_id = s.id FROM sessions s JOIN messages m ON m.session_id = s.id
WHERE m.active = 1 AND m.role IN ('user', 'assistant') WHERE m.active = 1 AND m.role IN ('user', 'assistant')
AND COALESCE(s.source, 'cron') != 'cron'
GROUP BY s.id GROUP BY s.id
HAVING n >= 2 HAVING n >= 2
ORDER BY COALESCE(s.last_activity_at, s.started_at) DESC ORDER BY {order_expr} DESC
LIMIT ?""", (MAX_HISTORY_SESSIONS,)).fetchall() LIMIT ?""", (MAX_HISTORY_SESSIONS,)).fetchall()
res["sessions_total"] = len(sessions) cron_sessions = db.execute(f"""
SELECT s.id, s.source, s.chat_type, s.display_name, s.title,
s.started_at, {last_expr} AS last_at, COUNT(m.id) n
FROM sessions s JOIN messages m ON m.session_id = s.id
WHERE m.active = 1 AND m.role IN ('user', 'assistant')
AND COALESCE(s.source, 'cron') = 'cron'
GROUP BY s.id
HAVING n >= 2
ORDER BY {order_expr} DESC
LIMIT ?""", (MAX_HISTORY_SESSIONS,)).fetchall()
all_sessions = list(sessions) + list(cron_sessions) # живые первыми
res["sessions_total"] = len(all_sessions)
hdir = os.path.join(out_dir, "history") hdir = os.path.join(out_dir, "history")
os.makedirs(hdir, exist_ok=True) os.makedirs(hdir, exist_ok=True)
idx_lines = ["# История диалогов Гермеса → Simbiot", idx_lines = ["# История диалогов Гермеса → Simbiot",
"", "сессии с реальным диалогом (active=1, ≥2 сообщения),", "", "сессии с реальным диалогом (active=1, ≥2 сообщения),",
f"капы: {MAX_HISTORY_MSGS_PER_SESSION}/сессия, {MAX_TOTAL_HISTORY_MSGS} всего", ""] f"капы: {MAX_HISTORY_MSGS_PER_SESSION}/сессия, {MAX_TOTAL_HISTORY_MSGS} всего", ""]
total = 0 total = 0
for s in sessions: for s in all_sessions:
if total >= MAX_TOTAL_HISTORY_MSGS: if total >= MAX_TOTAL_HISTORY_MSGS:
idx_lines.append(f"- (усечено: достигнут глобальный кап {MAX_TOTAL_HISTORY_MSGS} сообщений)") idx_lines.append(f"- (усечено: достигнут глобальный кап {MAX_TOTAL_HISTORY_MSGS} сообщений)")
break break
@ -183,7 +210,7 @@ def extract_history(hermes_dir: str, out_dir: str) -> dict:
total += len(msgs) total += len(msgs)
idx_lines.append(f"- [{title}]({os.path.basename(path)}) — " idx_lines.append(f"- [{title}]({os.path.basename(path)}) — "
f"{s['source'] or '?'}, {len(msgs)} сообщ., " f"{s['source'] or '?'}, {len(msgs)} сообщ., "
f"последнее {datetime.fromtimestamp(s['last_activity_at'] or s['started_at'] or 0, tz=timezone.utc).strftime('%Y-%m-%d')}") f"последнее {datetime.fromtimestamp(s['last_at'] or s['started_at'] or 0, tz=timezone.utc).strftime('%Y-%m-%d')}")
db.close() db.close()
with open(os.path.join(out_dir, "history-index.md"), "w", encoding="utf-8") as f: with open(os.path.join(out_dir, "history-index.md"), "w", encoding="utf-8") as f:
f.write("\n".join(idx_lines) + "\n") f.write("\n".join(idx_lines) + "\n")
@ -341,7 +368,7 @@ def main():
ap.add_argument("--rag-script", default="/root/rag/rag.py") ap.add_argument("--rag-script", default="/root/rag/rag.py")
args = ap.parse_args() args = ap.parse_args()
simbiot_repo = os.path.dirname(os.path.abspath(__file__)) simbiot_repo = REPO_ROOT
out_dir = args.out or os.path.join(simbiot_repo, "hermes-migration") out_dir = args.out or os.path.join(simbiot_repo, "hermes-migration")
if args.apply: if args.apply:
os.makedirs(out_dir, exist_ok=True) os.makedirs(out_dir, exist_ok=True)