feat(commands): /compact alias + --preview/--dry-run flags for /compress (#3243 salvage)
Some checks are pending
CI / Detect affected areas (push) Waiting to run
CI / Python tests (push) Blocked by required conditions
CI / Python lints (push) Blocked by required conditions
CI / TypeScript (push) Blocked by required conditions
CI / Docs Site (push) Blocked by required conditions
CI / Deny unrelated histories (push) Blocked by required conditions
CI / Check contributors (push) Blocked by required conditions
CI / Check uv.lock (push) Blocked by required conditions
CI / Lint Docker scripts (push) Blocked by required conditions
CI / Build&Test Docker image (push) Blocked by required conditions
CI / Supply-chain scan (push) Blocked by required conditions
CI / OSV scan (push) Waiting to run
CI / All required checks pass (push) Blocked by required conditions
CI / CI timing report (push) Blocked by required conditions
Deploy Site / deploy-vercel (push) Waiting to run
Deploy Site / deploy-docs (push) Waiting to run

Salvaged from PR #3243 by @Mibayy, reimplemented against current main
(the original diff targeted a removed gateway/run.py handler).

- /compact is now a first-class alias of /compress (CLI, gateway,
  Telegram/Slack/Discord command lists, autocomplete) — also fixes the
  dangling '/compact' references in gateway error messages
  (gateway/run.py context-exhausted banners).
- --preview / --dry-run: report what WOULD be compressed (message
  counts, token estimate, 'here [N]' boundary) without touching the
  transcript. Flags coexist with the existing 'here [N]' / focus-topic
  args on both the CLI and gateway surfaces via shared pure helpers in
  hermes_cli/partial_compress.py.
- --aggressive (LLM-free hard truncation) is intentionally NOT
  implemented: it would need its own transcript-persistence branch
  outside the guarded _compress_context rotation machinery (#44794
  data-loss class). The flag is recognized and returns an explanatory
  message pointing at '/compress here [N]' and /undo instead of being
  mis-parsed as a focus topic.
- locales: gateway.compress.aggressive_unsupported added to all 16
  catalogs (parity test enforced).
- release.py: AUTHOR_MAP entry for contributor credit.
This commit is contained in:
Mibayy 2026-07-02 04:47:47 -07:00 committed by Teknium
parent fb74ddf7fe
commit ce9aa869fc
23 changed files with 449 additions and 2 deletions

35
cli.py
View file

@ -9314,9 +9314,11 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
return
from hermes_cli.partial_compress import (
extract_compress_flags,
parse_partial_compress_args,
rejoin_compressed_head_and_tail,
split_history_for_partial_compress,
summarize_compress_preview,
)
# Args after the command word (e.g. "/compress here 3" -> "here 3").
@ -9326,9 +9328,42 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
if len(_parts) > 1:
raw_args = _parts[1].strip()
# Strip --preview/--dry-run/--aggressive before positional parsing
# so the flags coexist with 'here [N]' / focus-topic forms.
raw_args, preview, aggressive = extract_compress_flags(raw_args)
partial, keep_last, focus_topic = parse_partial_compress_args(raw_args)
focus_topic = focus_topic or ""
if aggressive:
# LLM-free hard truncation is not supported: it would need its
# own transcript-persistence path outside the guarded
# _compress_context rotation machinery. Surface that instead of
# silently mis-parsing the flag as a focus topic.
print("(._.) --aggressive is not supported; use '/compress here [N]' "
"to keep only recent exchanges, or /undo to drop turns.")
if not preview:
return
if preview:
from agent.model_metadata import estimate_request_tokens_rough
_sys_prompt = getattr(self.agent, "_cached_system_prompt", "") or ""
_tools = getattr(self.agent, "tools", None) or None
approx_tokens = estimate_request_tokens_rough(
self.conversation_history,
system_prompt=_sys_prompt,
tools=_tools,
)
report = summarize_compress_preview(
self.conversation_history,
partial,
keep_last,
focus_topic or None,
approx_tokens,
)
for line in report["lines"]:
print(f"🗜️ {line}")
return
original_count = len(self.conversation_history)
with self._busy_command("Compressing context..."):
try: