From fd3864d8bd512ffa21a671d99969a6e54dd91a02 Mon Sep 17 00:00:00 2001 From: Cyprian Kowalczyk Date: Fri, 24 Apr 2026 15:19:44 -0700 Subject: [PATCH] feat(cli): wrap /compress in _busy_command to block input during compression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this, typing during /compress was accepted by the classic CLI prompt and landed in the next prompt after compression finished, effectively consuming a keystroke for a prompt that was about to be replaced. Wrapping the body in self._busy_command('Compressing context...') blocks input rendering for the duration, matching the pattern /skills install and other slow commands already use. Salvages the useful part of #10303 (@iRonin). The `_compressing` flag added to run_agent.py in the original PR was dead code (set in 3 spots, read nowhere — not by cli.py, not by run_agent.py, not by the Ink TUI which doesn't use _busy_command at all) and was dropped. --- cli.py | 87 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/cli.py b/cli.py index 0b1bafe53..00937e9f9 100644 --- a/cli.py +++ b/cli.py @@ -7011,51 +7011,52 @@ class HermesCLI: focus_topic = parts[1].strip() original_count = len(self.conversation_history) - try: - from agent.model_metadata import estimate_messages_tokens_rough - from agent.manual_compression_feedback import summarize_manual_compression - original_history = list(self.conversation_history) - approx_tokens = estimate_messages_tokens_rough(original_history) - if focus_topic: - print(f"🗜️ Compressing {original_count} messages (~{approx_tokens:,} tokens), " - f"focus: \"{focus_topic}\"...") - else: - print(f"🗜️ Compressing {original_count} messages (~{approx_tokens:,} tokens)...") + with self._busy_command("Compressing context..."): + try: + from agent.model_metadata import estimate_messages_tokens_rough + from agent.manual_compression_feedback import summarize_manual_compression + original_history = list(self.conversation_history) + approx_tokens = estimate_messages_tokens_rough(original_history) + if focus_topic: + print(f"🗜️ Compressing {original_count} messages (~{approx_tokens:,} tokens), " + f"focus: \"{focus_topic}\"...") + else: + print(f"🗜️ Compressing {original_count} messages (~{approx_tokens:,} tokens)...") - compressed, _ = self.agent._compress_context( - original_history, - self.agent._cached_system_prompt or "", - approx_tokens=approx_tokens, - focus_topic=focus_topic or None, - ) - self.conversation_history = compressed - # _compress_context ends the old session and creates a new child - # session on the agent (run_agent.py::_compress_context). Sync the - # CLI's session_id so /status, /resume, exit summary, and title - # generation all point at the live continuation session, not the - # ended parent. Without this, subsequent end_session() calls target - # the already-closed parent and the child is orphaned. - if ( - getattr(self.agent, "session_id", None) - and self.agent.session_id != self.session_id - ): - self.session_id = self.agent.session_id - self._pending_title = None - new_tokens = estimate_messages_tokens_rough(self.conversation_history) - summary = summarize_manual_compression( - original_history, - self.conversation_history, - approx_tokens, - new_tokens, - ) - icon = "🗜️" if summary["noop"] else "✅" - print(f" {icon} {summary['headline']}") - print(f" {summary['token_line']}") - if summary["note"]: - print(f" {summary['note']}") + compressed, _ = self.agent._compress_context( + original_history, + self.agent._cached_system_prompt or "", + approx_tokens=approx_tokens, + focus_topic=focus_topic or None, + ) + self.conversation_history = compressed + # _compress_context ends the old session and creates a new child + # session on the agent (run_agent.py::_compress_context). Sync the + # CLI's session_id so /status, /resume, exit summary, and title + # generation all point at the live continuation session, not the + # ended parent. Without this, subsequent end_session() calls target + # the already-closed parent and the child is orphaned. + if ( + getattr(self.agent, "session_id", None) + and self.agent.session_id != self.session_id + ): + self.session_id = self.agent.session_id + self._pending_title = None + new_tokens = estimate_messages_tokens_rough(self.conversation_history) + summary = summarize_manual_compression( + original_history, + self.conversation_history, + approx_tokens, + new_tokens, + ) + icon = "🗜️" if summary["noop"] else "✅" + print(f" {icon} {summary['headline']}") + print(f" {summary['token_line']}") + if summary["note"]: + print(f" {summary['note']}") - except Exception as e: - print(f" ❌ Compression failed: {e}") + except Exception as e: + print(f" ❌ Compression failed: {e}") def _handle_debug_command(self): """Handle /debug — upload debug report + logs and print paste URLs."""