refactor: step 2 - extract domain services (tasks, prompts, snapshots, knowledge)

This commit is contained in:
2026-08-21 10:03:12 +03:00
parent 304208760b
commit 16928de5bd
19 changed files with 1204 additions and 518 deletions
+114
View File
@@ -0,0 +1,114 @@
"""
===============================================================================
FILE: services/prompts/repository.py
PROJECT: SCUD Orion AI (Unified Architecture)
MODULE: services / prompts
ROLE: Реляционное хранилище узлов системного промпта (таблица system_prompt_nodes).
AI-CONTEXT-ANCHORS:
- ANCHOR[PROMPT_REPO_GET_ACTIVE]: Сборка активного промпта из узлов БД.
- ANCHOR[PROMPT_REPO_APPLY_ACTION]: Точечная вставка / изменение / удаление узла.
===============================================================================
"""
import re
import logging
from typing import List, Tuple, Dict, Any
from core.connection import get_connection
logger = logging.getLogger("PROMPT_REPO")
# ANCHOR[PROMPT_REPO_GET_ACTIVE]
def repo_get_active_prompt(prompt_name: str = "main_agent") -> str:
"""Собирает структурированный текст системного промпта из активных узлов."""
with get_connection(row_factory=True) as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT section_id, item_id, content
FROM system_prompt_nodes
WHERE prompt_name = ? AND is_active = 1
ORDER BY section_id ASC, item_id ASC
""", (prompt_name,))
rows = cursor.fetchall()
if not rows:
return "Ты — ИИ-ассистент SCUD Orion AI."
lines = []
current_section = None
for r in rows:
sec_id = r["section_id"]
itm_id = r["item_id"]
content = r["content"]
if itm_id == 0:
if current_section is not None:
lines.append("")
lines.append(f"{sec_id}. {content}")
current_section = sec_id
else:
lines.append(f" {sec_id}.{itm_id}. {content}")
return "\n".join(lines)
# ANCHOR[PROMPT_REPO_APPLY_ACTION]
def repo_apply_prompt_action(action: str, section_id: int, item_id: int, content: str = "", prompt_name: str = "main_agent") -> None:
"""Точечно применяет действие (ADD / UPDATE / DELETE) над узлом промпта."""
with get_connection() as conn:
cursor = conn.cursor()
action_clean = (action or "").upper()
if action_clean in ["ADD", "UPDATE", "EDIT"]:
cursor.execute("""
INSERT INTO system_prompt_nodes (prompt_name, section_id, item_id, content, is_active, updated_at)
VALUES (?, ?, ?, ?, 1, CURRENT_TIMESTAMP)
ON CONFLICT(prompt_name, section_id, item_id) DO UPDATE SET
content = excluded.content,
is_active = 1,
updated_at = CURRENT_TIMESTAMP
""", (prompt_name, section_id, item_id, content))
elif action_clean == "DELETE":
cursor.execute("""
DELETE FROM system_prompt_nodes
WHERE prompt_name = ? AND section_id = ? AND item_id = ?
""", (prompt_name, section_id, item_id))
conn.commit()
def repo_save_full_prompt(prompt_text: str, prompt_name: str = "main_agent") -> None:
"""Парсит и полностью перезаписывает все узлы промпта из сырого текста."""
with get_connection() as conn:
cursor = conn.cursor()
cursor.execute("DELETE FROM system_prompt_nodes WHERE prompt_name = ?", (prompt_name,))
current_sec = 1
current_itm = 0
for raw_line in prompt_text.splitlines():
clean_line = re.sub(r'<[^>]+>', '', raw_line).strip()
if not clean_line:
continue
sub_match = re.match(r'^(\d+)[\.\s]+(\d+)[\.\s\:\-]+(.*)$', clean_line)
sec_match = re.match(r'^(\d+)[\.\s\:\-]+(.*)$', clean_line)
if sub_match:
current_sec = int(sub_match.group(1))
current_itm = int(sub_match.group(2))
content = sub_match.group(3).strip()
elif sec_match and not any(c.islower() for c in sec_match.group(2)[:15]):
current_sec = int(sec_match.group(1))
current_itm = 0
content = sec_match.group(2).strip()
else:
current_itm += 1
content = clean_line
cursor.execute("""
INSERT OR REPLACE INTO system_prompt_nodes (prompt_name, section_id, item_id, content, is_active)
VALUES (?, ?, ?, ?, 1)
""", (prompt_name, current_sec, current_itm, content))
conn.commit()