mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-25 19:20:16 +00:00
Merge pull request #2125 into stage-344
docs: clarify compression anchor helpers (closes #2093)
This commit is contained in:
@@ -1,5 +1,36 @@
|
||||
"""
|
||||
Shared helpers for session compression anchor metadata.
|
||||
|
||||
Manual compression anchoring versus automatic compression paths
|
||||
===============================================================
|
||||
|
||||
When ``auto_compression=True`` is passed to ``visible_messages_for_anchor()``,
|
||||
the function accepts a broader set of message content types (including
|
||||
provider-style ``input_text`` / ``output_text`` parts) and metadata markers
|
||||
(``reasoning``, ``thinking``, etc.) from any non-tool role. This enables the
|
||||
streaming auto-compression path to determine which messages should anchor
|
||||
compression UI metadata without being limited to the legacy manual-compression
|
||||
rules.
|
||||
|
||||
When ``auto_compression=False`` (the default), the function applies the
|
||||
historical manual-compression rules: only plain ``text`` content parts from
|
||||
non-assistant roles are counted.
|
||||
|
||||
Why this module exists
|
||||
======================
|
||||
|
||||
Compression anchoring needs to identify which messages in a session transcript
|
||||
are semantically significant enough to seed the compression UI metadata (e.g.,
|
||||
message count, token budget display). The original implementation hard-coded
|
||||
these rules in multiple places. This module consolidates the logic so that:
|
||||
|
||||
1. Manual compression anchoring (CLI/legacy path) uses the stricter ruleset.
|
||||
2. Automatic compression (streaming/agent path) can leverage the relaxed ruleset
|
||||
when it knows it is handling provider-style messages.
|
||||
|
||||
Callers specify ``auto_compression=True`` when the messages may originate from
|
||||
an automatic/compression-aware pipeline, and ``False`` (default) for manual
|
||||
compression contexts.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -41,7 +41,7 @@ _tls = threading.local()
|
||||
_SKILL_HOME_MODULES = ("tools.skills_tool", "tools.skill_manager_tool")
|
||||
|
||||
|
||||
def _patch_skill_home_modules(home: Path) -> None:
|
||||
def patch_skill_home_modules(home: Path) -> None:
|
||||
"""Patch imported skill modules that cache HERMES_HOME at import time."""
|
||||
for module_name in _SKILL_HOME_MODULES:
|
||||
module = sys.modules.get(module_name)
|
||||
@@ -628,7 +628,7 @@ def _set_hermes_home(home: Path):
|
||||
"""Set HERMES_HOME env var and monkey-patch cached module-level paths."""
|
||||
os.environ['HERMES_HOME'] = str(home)
|
||||
|
||||
_patch_skill_home_modules(home)
|
||||
patch_skill_home_modules(home)
|
||||
|
||||
# Patch cron/jobs module-level cache
|
||||
try:
|
||||
|
||||
+4
-4
@@ -2286,7 +2286,7 @@ def _run_agent_streaming(
|
||||
# process-level active-profile global. Falls back gracefully.
|
||||
try:
|
||||
from api.profiles import (
|
||||
_patch_skill_home_modules,
|
||||
patch_skill_home_modules,
|
||||
get_hermes_home_for_profile,
|
||||
get_profile_runtime_env,
|
||||
)
|
||||
@@ -2296,7 +2296,7 @@ def _run_agent_streaming(
|
||||
except ImportError:
|
||||
_profile_home = os.environ.get('HERMES_HOME', '')
|
||||
_profile_runtime_env = {}
|
||||
_patch_skill_home_modules = None
|
||||
patch_skill_home_modules = None
|
||||
|
||||
# Capture the resolved profile name now, while profile context is
|
||||
# reliable. Used in the compression migration block to stamp s.profile
|
||||
@@ -2349,8 +2349,8 @@ def _run_agent_streaming(
|
||||
# above, so we only do lightweight sys.modules lookups and
|
||||
# attribute assignments here — no first-time import under
|
||||
# the lock (#2024).
|
||||
if _patch_skill_home_modules is not None:
|
||||
_patch_skill_home_modules(Path(_profile_home))
|
||||
if patch_skill_home_modules is not None:
|
||||
patch_skill_home_modules(Path(_profile_home))
|
||||
# Lock released — agent runs without holding it
|
||||
# ── MCP Server Discovery (lazy import, idempotent) ──
|
||||
# MUST run AFTER the HERMES_HOME mutation above — `discover_mcp_tools()`
|
||||
|
||||
@@ -165,7 +165,7 @@ class TestSysModulesLookupInEnvLock:
|
||||
lock_lines.append(line)
|
||||
|
||||
lock_source = "\n".join(lock_lines)
|
||||
assert "_patch_skill_home_modules" in lock_source, (
|
||||
assert "patch_skill_home_modules" in lock_source, (
|
||||
"Inside `_ENV_LOCK`, streaming must use the shared skill module "
|
||||
"cache patch helper instead of duplicating module-specific logic "
|
||||
"(#2023/#2024)"
|
||||
@@ -179,15 +179,15 @@ class TestSysModulesLookupInEnvLock:
|
||||
node
|
||||
for node in ast.walk(tree)
|
||||
if isinstance(node, ast.FunctionDef)
|
||||
and node.name == "_patch_skill_home_modules"
|
||||
and node.name == "patch_skill_home_modules"
|
||||
),
|
||||
None,
|
||||
)
|
||||
assert helper is not None, "_patch_skill_home_modules() must be defined"
|
||||
assert helper is not None, "patch_skill_home_modules() must be defined"
|
||||
|
||||
helper_source = ast.get_source_segment(source, helper) or ""
|
||||
assert "sys.modules.get" in helper_source, (
|
||||
"_patch_skill_home_modules() must use sys.modules.get(), not import, "
|
||||
"patch_skill_home_modules() must use sys.modules.get(), not import, "
|
||||
"so env-lock callers do not trigger first-time imports (#2024)"
|
||||
)
|
||||
assert "HERMES_HOME" in helper_source
|
||||
|
||||
Reference in New Issue
Block a user