Major cleanup with GLM-5

This commit is contained in:
Alishahryar1 2026-02-28 09:10:21 -08:00
parent de70700dde
commit 744eec2772
14 changed files with 375 additions and 405 deletions

View file

@ -12,6 +12,11 @@ import time
from loguru import logger
from .commands import (
handle_clear_command,
handle_stats_command,
handle_stop_command,
)
from .event_parser import parse_cli_event
from .models import IncomingMessage
from .platforms.base import MessagingPlatform, SessionManagerInterface
@ -738,253 +743,12 @@ class ClaudeMessageHandler:
async def _handle_stop_command(self, incoming: IncomingMessage) -> None:
"""Handle /stop command from messaging platform."""
# Reply-scoped stop: reply "/stop" to stop only that task.
if incoming.is_reply() and incoming.reply_to_message_id:
reply_id = incoming.reply_to_message_id
tree = self.tree_queue.get_tree_for_node(reply_id)
node_id = self.tree_queue.resolve_parent_node_id(reply_id) if tree else None
if not node_id:
msg_id = await self.platform.queue_send_message(
incoming.chat_id,
self._format_status(
"", "Stopped.", "Nothing to stop for that message."
),
fire_and_forget=False,
message_thread_id=incoming.message_thread_id,
)
self._record_outgoing_message(
incoming.platform, incoming.chat_id, msg_id, "command"
)
return
count = await self.stop_task(node_id)
noun = "request" if count == 1 else "requests"
msg_id = await self.platform.queue_send_message(
incoming.chat_id,
self._format_status("", "Stopped.", f"Cancelled {count} {noun}."),
fire_and_forget=False,
message_thread_id=incoming.message_thread_id,
)
self._record_outgoing_message(
incoming.platform, incoming.chat_id, msg_id, "command"
)
return
# Global stop: legacy behavior (stop everything)
count = await self.stop_all_tasks()
msg_id = await self.platform.queue_send_message(
incoming.chat_id,
self._format_status(
"", "Stopped.", f"Cancelled {count} pending or active requests."
),
fire_and_forget=False,
message_thread_id=incoming.message_thread_id,
)
self._record_outgoing_message(
incoming.platform, incoming.chat_id, msg_id, "command"
)
await handle_stop_command(self, incoming)
async def _handle_stats_command(self, incoming: IncomingMessage) -> None:
"""Handle /stats command."""
stats = self.cli_manager.get_stats()
tree_count = self.tree_queue.get_tree_count()
ctx = self._get_render_ctx()
msg_id = await self.platform.queue_send_message(
incoming.chat_id,
"📊 "
+ ctx.bold("Stats")
+ "\n"
+ ctx.escape_text(f"• Active CLI: {stats['active_sessions']}")
+ "\n"
+ ctx.escape_text(f"• Message Trees: {tree_count}"),
fire_and_forget=False,
message_thread_id=incoming.message_thread_id,
)
self._record_outgoing_message(
incoming.platform, incoming.chat_id, msg_id, "command"
)
async def _handle_clear_branch(
self, incoming: IncomingMessage, branch_root_id: str
) -> None:
"""
Clear a branch (replied-to node + all descendants).
Order: cancel tasks, delete messages, remove branch, update session store.
"""
tree = self.tree_queue.get_tree_for_node(branch_root_id)
if not tree:
return
# 1) Cancel branch tasks (no stop_all)
cancelled = await self.tree_queue.cancel_branch(branch_root_id)
self._update_cancelled_nodes_ui(cancelled)
# 2) Collect message IDs from branch nodes only
msg_ids: set[str] = set()
branch_ids = tree.get_descendants(branch_root_id)
for nid in branch_ids:
node = tree.get_node(nid)
if node:
if node.incoming.message_id:
msg_ids.add(str(node.incoming.message_id))
if node.status_message_id:
msg_ids.add(str(node.status_message_id))
if incoming.message_id:
msg_ids.add(str(incoming.message_id))
# 3) Delete messages (best-effort)
await self._delete_message_ids(incoming.chat_id, msg_ids)
# 4) Remove branch from tree
removed, root_id, removed_entire_tree = await self.tree_queue.remove_branch(
branch_root_id
)
# 5) Update session store
try:
self.session_store.remove_node_mappings([n.node_id for n in removed])
if removed_entire_tree:
self.session_store.remove_tree(root_id)
else:
updated_tree = self.tree_queue.get_tree(root_id)
if updated_tree:
self.session_store.save_tree(root_id, updated_tree.to_dict())
except Exception as e:
logger.warning(f"Failed to update session store after branch clear: {e}")
async def _delete_message_ids(self, chat_id: str, msg_ids: set[str]) -> None:
"""Best-effort delete messages by ID. Sorts numeric IDs descending."""
if not msg_ids:
return
def _as_int(s: str) -> int | None:
try:
return int(str(s))
except Exception:
return None
numeric: list[tuple[int, str]] = []
non_numeric: list[str] = []
for mid in msg_ids:
n = _as_int(mid)
if n is None:
non_numeric.append(mid)
else:
numeric.append((n, mid))
numeric.sort(reverse=True)
ordered = [mid for _, mid in numeric] + non_numeric
batch_fn = getattr(self.platform, "queue_delete_messages", None)
if callable(batch_fn):
try:
CHUNK = 100
for i in range(0, len(ordered), CHUNK):
chunk = ordered[i : i + CHUNK]
await batch_fn(chat_id, chunk, fire_and_forget=False)
except Exception as e:
logger.debug(f"Batch delete failed: {type(e).__name__}: {e}")
else:
for mid in ordered:
try:
await self.platform.queue_delete_message(
chat_id, mid, fire_and_forget=False
)
except Exception as e:
logger.debug(
f"Delete failed for msg {mid}: {type(e).__name__}: {e}"
)
await handle_stats_command(self, incoming)
async def _handle_clear_command(self, incoming: IncomingMessage) -> None:
"""
Handle /clear command.
Reply-scoped: reply to a message to clear that branch (node + descendants).
Standalone: global clear (stop all, delete all chat messages, reset store).
"""
if incoming.is_reply() and incoming.reply_to_message_id:
reply_id = incoming.reply_to_message_id
tree = self.tree_queue.get_tree_for_node(reply_id)
branch_root_id = (
self.tree_queue.resolve_parent_node_id(reply_id) if tree else None
)
if not branch_root_id:
cancel_fn = getattr(self.platform, "cancel_pending_voice", None)
if cancel_fn is not None:
cancelled = await cancel_fn(incoming.chat_id, reply_id)
if cancelled is not None:
voice_msg_id, status_msg_id = cancelled
msg_ids_to_del: set[str] = {voice_msg_id, status_msg_id}
if incoming.message_id is not None:
msg_ids_to_del.add(str(incoming.message_id))
await self._delete_message_ids(incoming.chat_id, msg_ids_to_del)
msg_id = await self.platform.queue_send_message(
incoming.chat_id,
self._format_status(
"🗑", "Cleared.", "Voice note cancelled."
),
fire_and_forget=False,
message_thread_id=incoming.message_thread_id,
)
self._record_outgoing_message(
incoming.platform, incoming.chat_id, msg_id, "command"
)
return
msg_id = await self.platform.queue_send_message(
incoming.chat_id,
self._format_status(
"🗑", "Cleared.", "Nothing to clear for that message."
),
fire_and_forget=False,
message_thread_id=incoming.message_thread_id,
)
self._record_outgoing_message(
incoming.platform, incoming.chat_id, msg_id, "command"
)
return
await self._handle_clear_branch(incoming, branch_root_id)
return
# Global clear
# 1) Stop tasks first (ensures no more work is running).
await self.stop_all_tasks()
# 2) Clear chat: best-effort delete messages we can identify.
msg_ids: set[str] = set()
# Add any recorded message IDs for this chat (commands, command replies, etc).
try:
for mid in self.session_store.get_message_ids_for_chat(
incoming.platform, incoming.chat_id
):
if mid is not None:
msg_ids.add(str(mid))
except Exception as e:
logger.debug(f"Failed to read message log for /clear: {e}")
try:
msg_ids.update(
self.tree_queue.get_message_ids_for_chat(
incoming.platform, incoming.chat_id
)
)
except Exception as e:
logger.warning(f"Failed to gather messages for /clear: {e}")
# Also delete the command message itself.
if incoming.message_id is not None:
msg_ids.add(str(incoming.message_id))
await self._delete_message_ids(incoming.chat_id, msg_ids)
# 3) Clear persistent state and reset in-memory queue/tree state.
try:
self.session_store.clear_all()
except Exception as e:
logger.warning(f"Failed to clear session store: {e}")
self.tree_queue = TreeQueueManager(
queue_update_callback=self._update_queue_positions,
node_started_callback=self._mark_node_processing,
)
"""Handle /clear command."""
await handle_clear_command(self, incoming)