Phase 4-6: Dead code removal, performance, minor fixes

Phase 4:
- Remove legacy SessionRecord, _sessions, _msg_to_session from SessionStore
- Fix hardcoded provider in root endpoint (use settings.provider_type)
- Update session store tests

Phase 5:
- Use list-based string accumulation in ThinkingSegment, TextSegment, ToolCallSegment
- Cache MAX_MESSAGE_LOG_ENTRIES_PER_CHAT at SessionStore init
- Use iterative DFS in MessageTree.get_descendants

Phase 6:
- Add comment for abstract async generator workaround in BaseProvider
- Rename TELEGRAM_EDIT log tags to PLATFORM_EDIT in handler

Co-authored-by: Ali Khokhar <alishahryar2@gmail.com>
This commit is contained in:
Cursor Agent
2026-02-17 02:01:01 +00:00
parent 72b7e34999
commit bfc781e0ed
10 changed files with 75 additions and 128 deletions
+17 -64
View File
@@ -9,24 +9,10 @@ import json
import os
from datetime import datetime, timezone
from typing import Optional, Dict, List, Any
from dataclasses import dataclass, asdict
import threading
from loguru import logger
@dataclass
class SessionRecord:
"""A single session record."""
session_id: str
chat_id: str
initial_msg_id: str
last_msg_id: str
platform: str
created_at: str
updated_at: str
class SessionStore:
"""
Persistent storage for message ↔ Claude session mappings and message trees.
@@ -38,10 +24,6 @@ class SessionStore:
def __init__(self, storage_path: str = "sessions.json"):
self.storage_path = storage_path
self._lock = threading.Lock()
self._sessions: Dict[str, SessionRecord] = {}
self._msg_to_session: Dict[
str, str
] = {} # "platform:chat_id:msg_id" -> session_id
self._trees: Dict[str, dict] = {} # root_id -> tree data
self._node_to_tree: Dict[str, str] = {} # node_id -> root_id
# Per-chat message ID log used to support best-effort UI clearing (/clear).
@@ -51,12 +33,15 @@ class SessionStore:
self._dirty = False
self._save_timer: Optional[threading.Timer] = None
self._save_debounce_secs = 0.5
cap_raw = os.getenv("MAX_MESSAGE_LOG_ENTRIES_PER_CHAT", "").strip()
try:
self._message_log_cap: Optional[int] = (
int(cap_raw) if cap_raw else None
)
except ValueError:
self._message_log_cap = None
self._load()
def _make_key(self, platform: str, chat_id: str, msg_id: str) -> str:
"""Create a unique key from platform, chat_id and msg_id."""
return f"{platform}:{chat_id}:{msg_id}"
def _make_chat_key(self, platform: str, chat_id: str) -> str:
return f"{platform}:{chat_id}"
@@ -69,25 +54,6 @@ class SessionStore:
with open(self.storage_path, "r", encoding="utf-8") as f:
data = json.load(f)
# Load sessions (legacy support)
for sid, record_data in data.get("sessions", {}).items():
if "platform" not in record_data:
record_data["platform"] = "telegram"
for field in ["chat_id", "initial_msg_id", "last_msg_id"]:
if isinstance(record_data.get(field), int):
record_data[field] = str(record_data[field])
record = SessionRecord(**record_data)
self._sessions[sid] = record
self._msg_to_session[
self._make_key(
record.platform, record.chat_id, record.initial_msg_id
)
] = sid
self._msg_to_session[
self._make_key(record.platform, record.chat_id, record.last_msg_id)
] = sid
# Load trees
self._trees = data.get("trees", {})
self._node_to_tree = data.get("node_to_tree", {})
@@ -124,8 +90,8 @@ class SessionStore:
self._message_log_ids[chat_key] = seen
logger.info(
f"Loaded {len(self._sessions)} sessions, {len(self._trees)} trees, "
f"and {sum(len(v) for v in self._message_log.values())} msg_ids from {self.storage_path}"
f"Loaded {len(self._trees)} trees and "
f"{sum(len(v) for v in self._message_log.values())} msg_ids from {self.storage_path}"
)
except Exception as e:
logger.error(f"Failed to load sessions: {e}")
@@ -134,9 +100,6 @@ class SessionStore:
"""Persist sessions and trees to disk. Caller must hold self._lock."""
try:
data = {
"sessions": {
sid: asdict(record) for sid, record in self._sessions.items()
},
"trees": self._trees,
"node_to_tree": self._node_to_tree,
"message_log": self._message_log,
@@ -211,22 +174,14 @@ class SessionStore:
seen.add(mid)
# Optional cap to prevent unbounded growth if configured.
# Default is unlimited as requested.
try:
cap_raw = os.getenv("MAX_MESSAGE_LOG_ENTRIES_PER_CHAT", "").strip()
if cap_raw:
cap = int(cap_raw)
if cap > 0:
items = self._message_log.get(chat_key, [])
if len(items) > cap:
# Drop oldest entries and rebuild seen set.
self._message_log[chat_key] = items[-cap:]
self._message_log_ids[chat_key] = {
str(x.get("message_id"))
for x in self._message_log[chat_key]
}
except Exception:
pass
if self._message_log_cap is not None and self._message_log_cap > 0:
items = self._message_log.get(chat_key, [])
if len(items) > self._message_log_cap:
self._message_log[chat_key] = items[-self._message_log_cap :]
self._message_log_ids[chat_key] = {
str(x.get("message_id"))
for x in self._message_log[chat_key]
}
self._schedule_save()
@@ -244,8 +199,6 @@ class SessionStore:
def clear_all(self) -> None:
"""Clear all stored sessions/trees/mappings and persist an empty store."""
with self._lock:
self._sessions.clear()
self._msg_to_session.clear()
self._trees.clear()
self._node_to_tree.clear()
self._message_log.clear()