refactor(hermes_cli): unify resume state restore, fold trivial locals and module docstrings in g6 files
This commit is contained in:
+2
-3
@@ -402,10 +402,9 @@ def _cmd_cleanup(args):
|
||||
print_error(f"Could not archive: {e}")
|
||||
print_info(f"Try manually: mv {source_dir} {source_dir}.pre-migration")
|
||||
print()
|
||||
n = len(dirs_to_check) if dry_run else total_archived
|
||||
word = "directory" if n == 1 else "directories"
|
||||
word = "directory" if (len(dirs_to_check) if dry_run else total_archived) == 1 else "directories"
|
||||
if dry_run:
|
||||
_info(f"Dry run complete. {n} {word} would be archived.",
|
||||
_info(f"Dry run complete. {len(dirs_to_check)} {word} would be archived.",
|
||||
"Run without --dry-run to archive them.")
|
||||
elif total_archived:
|
||||
print_success(f"Cleaned up {total_archived} OpenClaw {word}.")
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
"""Agent-construction and session-resume display methods for ``HermesCLI``.
|
||||
|
||||
Runtime-credential resolution, per-turn agent config, first-use agent construction, and
|
||||
resumed-session preload + history recap. ``cli.py`` helpers are imported lazily inside
|
||||
each method so this module never imports ``cli`` at import time (import cycle).
|
||||
"""
|
||||
"""Agent construction + session-resume display for ``HermesCLI``: credential resolution,
|
||||
per-turn agent config, first-use build, resume preload + recap. ``cli.py`` helpers are
|
||||
imported lazily inside each method (import cycle)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -202,8 +199,7 @@ class CLIAgentSetupMixin:
|
||||
list(runtime.get("args") or []))
|
||||
# A callable api_key is a bearer-token provider (Azure Entra ID): the OpenAI SDK
|
||||
# invokes it per request, so skip string validation / placeholder substitution.
|
||||
_is_callable_provider = callable(api_key) and not isinstance(api_key, str)
|
||||
if not _is_callable_provider and (not isinstance(api_key, str) or not api_key):
|
||||
if not callable(api_key) and not (isinstance(api_key, str) and api_key):
|
||||
if _keyless_custom_base(base_url):
|
||||
# Placeholder key so the SDK doesn't reject the keyless local endpoint.
|
||||
api_key = "no-key-required"
|
||||
@@ -314,7 +310,7 @@ class CLIAgentSetupMixin:
|
||||
return False
|
||||
api_key = runtime.get("api_key")
|
||||
base_url = runtime.get("base_url")
|
||||
if (callable(api_key) and not isinstance(api_key, str)) or (isinstance(api_key, str) and api_key):
|
||||
if callable(api_key) or (isinstance(api_key, str) and api_key):
|
||||
return bool(base_url)
|
||||
return _keyless_custom_base(base_url)
|
||||
|
||||
@@ -394,6 +390,12 @@ class CLIAgentSetupMixin:
|
||||
session_meta = self._session_db.get_session(self.session_id) or session_meta
|
||||
return session_meta
|
||||
|
||||
def _restore_session_state(self, session_meta, *, quiet: bool = False) -> None:
|
||||
"""Restore cwd / yolo / model from the resumed session's metadata."""
|
||||
self._restore_session_cwd(session_meta, quiet=quiet)
|
||||
self._restore_session_yolo(session_meta, quiet=quiet)
|
||||
self._restore_session_model(session_meta, quiet=quiet)
|
||||
|
||||
def _reopen_session(self) -> None:
|
||||
"""Clear ended_at so the resumed session is active again (best effort)."""
|
||||
try:
|
||||
@@ -453,9 +455,7 @@ class CLIAgentSetupMixin:
|
||||
f"↻ Resumed session {self.session_id}{title_part} {counts}",
|
||||
f"[bold {_accent_hex()}]↻ Resumed session[/] [bold]{_escape(self.session_id)}[/]"
|
||||
f"[bold {_accent_hex()}]{_escape(title_part)}[/] {counts}")
|
||||
self._restore_session_cwd(session_meta, quiet=_quiet_mode)
|
||||
self._restore_session_yolo(session_meta, quiet=_quiet_mode)
|
||||
self._restore_session_model(session_meta, quiet=_quiet_mode)
|
||||
self._restore_session_state(session_meta, quiet=_quiet_mode)
|
||||
else:
|
||||
_say(
|
||||
f"Session {self.session_id} found but has no messages. Starting fresh.",
|
||||
@@ -555,7 +555,7 @@ class CLIAgentSetupMixin:
|
||||
self._active_agent_route_signature = _route_signature(effective_model, runtime)
|
||||
|
||||
# Force-create DB row on /title intent, then apply title.
|
||||
if self._pending_title and self._session_db and self.agent:
|
||||
if self._pending_title and self._session_db:
|
||||
try:
|
||||
self.agent._ensure_db_session()
|
||||
if self.agent._session_db_created:
|
||||
@@ -589,10 +589,7 @@ class CLIAgentSetupMixin:
|
||||
safety_check = getattr(self._session_db, "assert_resume_safe", None)
|
||||
if not callable(safety_check):
|
||||
return None
|
||||
if tip_only:
|
||||
safety_check(self.session_id, tip_only=True)
|
||||
else:
|
||||
safety_check(self.session_id)
|
||||
safety_check(self.session_id, **({"tip_only": True} if tip_only else {}))
|
||||
except SessionResumeTooLargeError as exc:
|
||||
return str(exc)
|
||||
except Exception as exc:
|
||||
@@ -634,7 +631,6 @@ class CLIAgentSetupMixin:
|
||||
self.conversation_history = restored
|
||||
self._resume_display_history = [m for m in display_history if m.get("role") != "session_meta"]
|
||||
from agent.context_compressor import is_user_originated_turn
|
||||
|
||||
# Count only user-originated turns: legacy compaction handoffs are durable
|
||||
# role=user rows without display_kind.
|
||||
msg_count = len([m for m in self._resume_display_history if is_user_originated_turn(m)])
|
||||
@@ -644,9 +640,7 @@ class CLIAgentSetupMixin:
|
||||
f"{title_part} "
|
||||
f"({msg_count} user message{'s' if msg_count != 1 else ''}, "
|
||||
f"{len(restored)} total messages)[/]")
|
||||
self._restore_session_cwd(session_meta)
|
||||
self._restore_session_yolo(session_meta)
|
||||
self._restore_session_model(session_meta)
|
||||
self._restore_session_state(session_meta)
|
||||
self._reopen_session()
|
||||
return True
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
"""Simple slash-command wrappers plus goal/heartbeat/loop manager hooks for the interactive CLI
|
||||
|
||||
Mixin bound onto ``HermesCLI`` via the MRO. cli.py-internal symbols are imported LAZILY
|
||||
inside each method (``from cli import ...``) — never at module load (import cycle).
|
||||
"""
|
||||
"""Simple slash-command wrappers plus goal/heartbeat/loop manager hooks for the interactive CLI.
|
||||
Mixin on ``HermesCLI``; cli.py symbols are imported lazily inside methods (import cycle)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -198,14 +195,12 @@ class CLILoopsMixin:
|
||||
|
||||
def _cmd_egress(self, cmd_original: str):
|
||||
from hermes_cli.slash_exec import CommandContext, execute_command
|
||||
self._console_print(
|
||||
execute_command("egress", CommandContext(surface="cli")).text,
|
||||
highlight=False, markup=False)
|
||||
text = execute_command("egress", CommandContext(surface="cli")).text
|
||||
self._console_print(text, highlight=False, markup=False)
|
||||
|
||||
def _cmd_statusbar(self, cmd_original: str):
|
||||
self._status_bar_visible = not self._status_bar_visible
|
||||
state = "visible" if self._status_bar_visible else "hidden"
|
||||
self._console_print(f" Status bar {state}")
|
||||
self._console_print(f" Status bar {'visible' if self._status_bar_visible else 'hidden'}")
|
||||
|
||||
def _cmd_update(self, cmd_original: str) -> bool:
|
||||
# A truthy result means the process is relaunching — leave the REPL.
|
||||
@@ -276,10 +271,8 @@ class CLILoopsMixin:
|
||||
_cprint(" Usage: /queue <prompt>")
|
||||
else:
|
||||
self._pending_input.put(payload)
|
||||
if self._agent_running:
|
||||
_cprint(f" Queued for the next turn: {_preview(payload)}")
|
||||
else:
|
||||
_cprint(f" Queued: {_preview(payload)}")
|
||||
when = " for the next turn" if self._agent_running else ""
|
||||
_cprint(f" Queued{when}: {_preview(payload)}")
|
||||
|
||||
def _cmd_steer(self, cmd_original: str):
|
||||
# Inject a message after the next tool call without interrupting: while the
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
"""Terminal repaint/resize recovery, input-mode healing, and clipboard helpers for the interactive CLI
|
||||
|
||||
Mixin bound onto ``HermesCLI`` via the MRO. cli.py-internal symbols are imported LAZILY
|
||||
inside each method (``from cli import ...``) — never at module load (import cycle).
|
||||
"""
|
||||
"""Terminal repaint/resize recovery, input-mode healing, and clipboard helpers for the interactive
|
||||
CLI. Mixin on ``HermesCLI``; cli.py symbols are imported lazily inside methods (import cycle)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -90,9 +87,7 @@ class CLITerminalMixin:
|
||||
throttled or resize-gated entry paint is silently dropped, so the prompt never
|
||||
renders and times out unseen (#41098).
|
||||
"""
|
||||
if getattr(self, "_terminal_io_broken", False):
|
||||
return
|
||||
if getattr(self, "_resize_recovery_pending", False):
|
||||
if getattr(self, "_terminal_io_broken", False) or getattr(self, "_resize_recovery_pending", False):
|
||||
return
|
||||
now = time.monotonic()
|
||||
if hasattr(self, "_app") and self._app and (now - getattr(self, "_last_invalidate", 0.0)) >= min_interval:
|
||||
@@ -155,9 +150,8 @@ class CLITerminalMixin:
|
||||
"""
|
||||
from cli import CLI_CONFIG
|
||||
display_config = CLI_CONFIG.get("display") if isinstance(CLI_CONFIG, dict) else {}
|
||||
if not isinstance(display_config, dict):
|
||||
display_config = {}
|
||||
raw = display_config.get("cli_rebuild_scrollback_on_redraw", False)
|
||||
raw = (display_config.get("cli_rebuild_scrollback_on_redraw", False)
|
||||
if isinstance(display_config, dict) else False)
|
||||
if isinstance(raw, str):
|
||||
return raw.strip().lower() in {"1", "true", "yes", "on", "always"}
|
||||
return bool(raw)
|
||||
|
||||
@@ -176,8 +176,7 @@ def render_codex_toml_section(
|
||||
"""
|
||||
out = [MIGRATION_MARKER]
|
||||
if not servers and not plugins and not default_permission_profile:
|
||||
out.append("# (no MCP servers, plugins, or permissions configured by Hermes)")
|
||||
out.append(MIGRATION_END_MARKER)
|
||||
out += ["# (no MCP servers, plugins, or permissions configured by Hermes)", MIGRATION_END_MARKER]
|
||||
return "\n".join(out) + "\n"
|
||||
if default_permission_profile:
|
||||
profile = default_permission_profile
|
||||
|
||||
Reference in New Issue
Block a user