dheraingoud's picture
feat: synchronize proxy with upstream commits up to 5305bd7 and integrate NIM key rotator
0a54372
Raw
History Blame Contribute Delete
5.91 kB
"""Command handlers for messaging platform commands (/stop, /stats, /clear).
Commands depend on MessagingCommandContext instead of the concrete workflow.
"""
from loguru import logger
from .command_context import MessagingCommandContext
from .models import IncomingMessage
async def _send_stop_feedback(
handler: MessagingCommandContext,
incoming: IncomingMessage,
suffix: str,
) -> None:
"""Send stop feedback only when no existing status can represent the result."""
msg_id = await handler.outbound.queue_send_message(
incoming.chat_id,
handler.format_status("⏹", "Stopped.", suffix),
fire_and_forget=False,
message_thread_id=incoming.message_thread_id,
)
handler.record_outgoing_message(
incoming.platform, incoming.chat_id, msg_id, "command"
)
async def handle_stop_command(
handler: MessagingCommandContext, 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:
outcome = await handler.stop_reply(
incoming.scope,
incoming.reply_to_message_id,
)
if outcome.cancelled_count == 0:
await _send_stop_feedback(
handler,
incoming,
"Nothing to stop for that message.",
)
return
if outcome.requires_confirmation(incoming.scope):
noun = "request" if outcome.cancelled_count == 1 else "requests"
await _send_stop_feedback(
handler,
incoming,
f"Cancelled {outcome.cancelled_count} {noun}.",
)
return
# Global stop: legacy behavior (stop everything)
outcome = await handler.stop_all_tasks()
if outcome.cancelled_count == 0:
await _send_stop_feedback(handler, incoming, "Nothing to stop.")
elif outcome.requires_confirmation(incoming.scope):
noun = "request" if outcome.cancelled_count == 1 else "requests"
await _send_stop_feedback(
handler,
incoming,
f"Cancelled {outcome.cancelled_count} pending or active {noun}.",
)
async def handle_stats_command(
handler: MessagingCommandContext, incoming: IncomingMessage
) -> None:
"""Handle /stats command."""
stats = handler.cli_manager.get_stats()
tree_count = handler.get_tree_count()
ctx = handler.get_render_ctx()
msg_id = await handler.outbound.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,
)
handler.record_outgoing_message(
incoming.platform, incoming.chat_id, msg_id, "command"
)
async def _delete_message_ids(
handler: MessagingCommandContext, 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)
non_numeric.sort(reverse=True)
ordered = [mid for _, mid in numeric] + non_numeric
failed = 0
try:
await handler.outbound.queue_delete_messages(
chat_id,
ordered,
fire_and_forget=False,
)
except Exception as e:
failed = len(ordered)
logger.debug("Message delete failed for chat {}: {}", chat_id, type(e).__name__)
if ordered:
logger.info(
"Clear delete attempted={} failed={}",
len(ordered),
failed,
)
async def handle_clear_command(
handler: MessagingCommandContext, incoming: IncomingMessage
) -> None:
"""
Handle /clear command.
Reply-scoped: delete the selected message and its literal reply subtree.
Standalone: reset and delete the invoking chat's managed conversation.
"""
if incoming.is_reply() and incoming.reply_to_message_id:
result = await handler.clear_reply(
incoming.scope,
incoming.reply_to_message_id,
)
if result is None:
msg_id = await handler.outbound.queue_send_message(
incoming.chat_id,
handler.format_status(
"🗑", "Cleared.", "Nothing to clear for that message."
),
fire_and_forget=False,
message_thread_id=incoming.message_thread_id,
)
handler.record_outgoing_message(
incoming.platform, incoming.chat_id, msg_id, "command"
)
return
delete_message_ids = set(result.delete_message_ids)
if incoming.message_id is not None:
delete_message_ids.add(str(incoming.message_id))
await _delete_message_ids(handler, incoming.chat_id, delete_message_ids)
handler.forget_tracked_message_ids(
incoming.platform,
incoming.chat_id,
delete_message_ids,
)
return
msg_ids = set(await handler.clear_chat(incoming.platform, incoming.chat_id))
# Also delete the command message itself.
if incoming.message_id is not None:
msg_ids.add(str(incoming.message_id))
await _delete_message_ids(handler, incoming.chat_id, msg_ids)