feat(llm): двухфазный жизненный цикл сессий, двусторонний Diff, Topic Drift Guard и актуализация документации

This commit is contained in:
2026-08-18 13:47:26 +03:00
parent 828ce67817
commit 4b1b8a3586
20 changed files with 1763 additions and 2006 deletions
+59 -10
View File
@@ -51,12 +51,12 @@ def print_stats():
print("=" * 60)
with get_connection() as conn:
cursor = conn.cursor()
tables = ['scud_logs', 'zup_staff', 'zup_absences', 'anomalies_history', 'ai_knowledge_base', 'chat_messages', 'session_states']
tables = ['scud_logs', 'zup_staff', 'zup_absences', 'anomalies_history', 'ai_knowledge_base', 'chat_messages', 'session_states', 'system_prompt_nodes', 'tasks']
for t in tables:
try:
cursor.execute(f"SELECT COUNT(*) FROM {t}")
cnt = cursor.fetchone()[0]
print(f" • Таблица [{t:<18}]: {cnt:>6} записей")
print(f" • Таблица [{t:<20}]: {cnt:>6} записей")
except Exception:
pass
print("=" * 60 + "\n")
@@ -151,7 +151,7 @@ def inspect_scud(snapshot_id=None, date_str=None, export_xlsx=None):
df = load_scud_from_db_by_snapshot(target_date, snapshot_param=snapshot_id)
if df.empty:
print(f"Записи СКУД не найдены.")
print("Записи СКУД не найдены.")
print("=" * 90 + "\n")
return
@@ -318,7 +318,6 @@ def print_chat_messages(session_id=None, limit=50):
if not rows:
print("Таблица chat_messages пуста.")
else:
# Если выводили все без конкретной сессии в порядке DESC, развернем для читаемости
if not session_id:
rows = list(reversed(rows))
@@ -327,13 +326,53 @@ def print_chat_messages(session_id=None, limit=50):
eph_marker = " [ЭФЕМЕРНОЕ]" if ephemeral else ""
print(f"[{msg_id}] {created} | Сессия: {sess} | Роль: {role.upper()}{eph_marker}")
print("-" * 105)
# Выводим контент, ограничивая длинные сообщения при необходимости
content_preview = content if content else ""
print(f"{content_preview}")
print("=" * 105)
print("\n")
def purge_chat_context(session_id=None, purge_all=False):
"""
Очистка контекста сообщений:
- По умолчанию: удаляет эфемерные сообщения, осиротевшие превью и сбрасывает стейты сессий.
- purge_all=True (--all): полностью очищает всю таблицу chat_messages и сбрасывает сессии.
"""
with get_connection() as conn:
cursor = conn.cursor()
if purge_all:
if session_id:
cursor.execute("DELETE FROM chat_messages WHERE session_id = ?", (session_id,))
cursor.execute("DELETE FROM session_states WHERE session_id = ?", (session_id,))
else:
cursor.execute("DELETE FROM chat_messages")
cursor.execute("DELETE FROM session_states")
deleted_msgs = cursor.rowcount
conn.commit()
print(f"\n[✓] Полная очистка истории выполнена! Удалено сообщений: {deleted_msgs}\n")
return
query = """
DELETE FROM chat_messages
WHERE is_ephemeral = 1
OR content LIKE '%Предпросмотр изменений%'
OR content LIKE '%Удален пункт:%'
OR content LIKE '%добавлен пункт:%'
"""
if session_id:
cursor.execute(query + " AND session_id = ?", (session_id,))
cursor.execute("DELETE FROM session_states WHERE session_id = ?", (session_id,))
else:
cursor.execute(query)
cursor.execute("DELETE FROM session_states")
deleted_msgs = cursor.rowcount
conn.commit()
print(f"\n[✓] Умная зачистка контекста выполнена! Удалено сообщений: {deleted_msgs}\n")
HELP_TEXT = """
CLI-утилита инспекции и управления SQLite базой данных СКУД (scud_orion_ai.db)
@@ -348,6 +387,7 @@ CLI-утилита инспекции и управления SQLite базой
tools -- Посмотреть реестр действий инструментов и кнопок (tool_action_registry)
sessions -- Посмотреть активные сессии и превью (session_states)
context [session_id] [--limit N] -- Посмотреть таблицу контекста сообщений чата (chat_messages)
context purge [session_id] [--all] -- Очистить контекст (умная зачистка или полная с флагом --all)
dump [output.xlsx] -- Полный дамп всех таблиц БД в многостраничный Excel
snapshot del [ID] или [--day ДД.ММ.ГГГГ] -- Удаление снапшота по ID или всех за выбранный день
@@ -360,6 +400,9 @@ CLI-утилита инспекции и управления SQLite базой
python scripts/db_cli.py tools
python scripts/db_cli.py sessions
python scripts/db_cli.py context web_session_main --limit 20
python scripts/db_cli.py context purge
python scripts/db_cli.py context purge --all
python scripts/db_cli.py context purge web_session_main --all
python scripts/db_cli.py snapshot del Y20260805-007
python scripts/db_cli.py dump my_dump.xlsx
"""
@@ -376,12 +419,13 @@ def main():
add_help=False
)
parser.add_argument('command', nargs='?', default=None, choices=['stats', 'snapshots', 'scud', 'absences', 'anomalies', 'rules', 'prompts', 'sessions', 'dump', 'snapshot', 'tools', 'context'], help="Основная команда")
parser.add_argument('action', nargs='?', default=None, help="Дополнительное действие (например, 'del') или session_id для контекста")
parser.add_argument('param', nargs='?', default=None, help="Параметр (дата, ID снапшота или имя файла)")
parser.add_argument('action', nargs='?', default=None, help="Дополнительное действие (например, 'del', 'purge') или session_id для контекста")
parser.add_argument('param', nargs='?', default=None, help="Параметр (дата, ID снапшота, session_id, '--all' или имя файла)")
parser.add_argument('--snapshot', type=str, default=None, help="ID конкретного снапшота для инспекции")
parser.add_argument('--export-xlsx', type=str, default=None, help="Экспорт среза СКУД в Excel-файл")
parser.add_argument('--day', type=str, default=None, help="Удалить снапшоты за конкретный день (ДД.ММ.ГГГГ)")
parser.add_argument('--limit', type=int, default=50, help="Лимит выводимых сообщений чата (для команды context)")
parser.add_argument('--all', action='store_true', help="Полная очистка всех сообщений (для команды context purge)")
if len(sys.argv) == 1:
print_stats()
@@ -410,8 +454,13 @@ def main():
elif args.command == 'tools':
print_tool_actions()
elif args.command == 'context':
sess_id = args.action if args.action else None
print_chat_messages(session_id=sess_id, limit=args.limit)
if args.action in ['purge', 'clear']:
is_all = args.all or (args.param == '--all')
sess_id = None if (args.param == '--all' or not args.param) else args.param
purge_chat_context(session_id=sess_id, purge_all=is_all)
else:
sess_id = args.action if args.action else None
print_chat_messages(session_id=sess_id, limit=args.limit)
elif args.command == 'dump':
filename = args.param if args.param else "db_dump_full.xlsx"
dump_all_to_excel(filename)
@@ -428,7 +477,7 @@ def main():
print(f"\n[❌] Ошибка: Неизвестное действие '{args.action}' для команды snapshot.")
print("Используйте: python scripts/db_cli.py snapshot del [ID или --day 'ДД.ММ.ГГГГ']\n")
else:
print(f"\n[❌] Ошибка: Неизвестная команда.")
print("\n[❌] Ошибка: Неизвестная команда.")
print(HELP_TEXT)
if __name__ == "__main__":