| |
|
|
| from datetime import datetime, timedelta, UTC |
| from difflib import SequenceMatcher |
| from typing import Optional, List, Dict |
|
|
| STAGNATION_WINDOW = 5 |
| STAGNATION_THRESHOLD = 0.95 |
|
|
|
|
| def get_last_responses(db, limit=STAGNATION_WINDOW) -> List[str]: |
| records = db.get_llm_recent_responses(limit=limit) |
| return [r["content"] if isinstance(r, dict) else r for r in records] |
|
|
|
|
| def is_stagnant(responses: List[str]) -> bool: |
| if len(responses) < 2: |
| return False |
|
|
| similarities = [] |
| for i in range(len(responses) - 1): |
| sim = string_similarity(responses[i], responses[i + 1]) |
| similarities.append(sim) |
|
|
| avg_sim = sum(similarities) / len(similarities) |
| return avg_sim >= STAGNATION_THRESHOLD |
|
|
|
|
| def string_similarity(a: str, b: str) -> float: |
| return SequenceMatcher(None, a.strip(), b.strip()).ratio() |
|
|
|
|
| def get_last_stagnation_info(db) -> Optional[Dict]: |
| responses = get_last_responses(db) |
| if is_stagnant(responses): |
| return { |
| "detected": True, |
| "average_similarity": round(sum( |
| string_similarity(responses[i], responses[i+1]) |
| for i in range(len(responses)-1) |
| ) / (len(responses)-1), 4), |
| "last_messages": responses |
| } |
| return {"detected": False} |
|
|
|
|
| def add_to_llm_memory(db, title: str, content: str, tags: str = "meta"): |
| db.insert("llm_memory", { |
| "title": title, |
| "content": content, |
| "tags": tags, |
| "created_at": datetime.now(UTC).isoformat(), |
| "updated_at": datetime.now(UTC).isoformat() |
| }) |
|
|
|
|
| def record_reflection_if_stagnant(db): |
| stagnation = get_last_stagnation_info(db) |
| if stagnation.get("detected"): |
| content = f"Обнаружена стагнация размышлений. Последние сообщения были очень похожи.\n\n" |
| content += "---\n" + "\n---\n".join(stagnation["last_messages"]) |
| add_to_llm_memory(db, "Стагнация размышлений", content, tags="meta,warning") |
| return True |
| return False |
|
|