fix(gateway): legacy checkpoints: true signature carries the default limits, one cfg_get per key

#119406 made absent keys carry DEFAULT_CONFIG's value in the cache signature, but the
legacy bool branch still emitted None for max_snapshots/max_total_size_mb/max_file_size_mb
while `_checkpoint_agent_kwargs` builds that agent from DEFAULT_CONFIG — so migrating to
`checkpoints: {enabled: true}` rebuilt the cached agent for nothing. The dict/absent branches
were also re-implementing cfg_get's own semantics; one `cfg_get(cfg, section, key, default=…)`
covers absent section, non-dict section, absent key and explicit null. DEFAULT_CONFIG is
imported at module top (hermes_cli.config already is; gateway/restart.py sets the precedent).
This commit is contained in:
kshitijk4poor
2026-09-23 00:13:40 +05:30
committed by kshitij
parent 79ec1f2a34
commit e1c71bd4fc
2 changed files with 26 additions and 31 deletions

View File

@@ -16,7 +16,7 @@ from agent.interrupt_compat import _accepts_keyword
from gateway.config import Platform
from gateway.session import SessionSource, build_session_context_prompt
from gateway.run_shutdown import _log_suppressed
from hermes_cli.config import cfg_get
from hermes_cli.config import DEFAULT_CONFIG, cfg_get
from hermes_cli.local_runtime.endpoint import LLAMACPP_ALIASES
if TYPE_CHECKING: # string annotations only; never imported at runtime (cycle)
@@ -48,24 +48,20 @@ class GatewayAgentCacheMixin:
@classmethod
def _extract_cache_busting_config(cls, user_config: dict | None) -> dict:
"""Values that must bust the cached agent, as a flat dict keyed by 'section.key'. ``user_config``
is the raw file (no DEFAULT_CONFIG merge), so an absent key is filled from DEFAULT_CONFIG — the
value the agent was actually built with. Mapping 'absent' to None made an explicit ``null``
(the documented opt-out of a non-None default such as ``compression.threshold_tokens``)
signature-identical to 'unset', so the opt-out never rebuilt a live session. Non-dict sections
count as absent. Includes the live tool registry generation: MCP reloads mutate the registry
without touching config.yaml."""
from hermes_cli.config import DEFAULT_CONFIG
is the raw file (no DEFAULT_CONFIG merge), so absent keys and non-dict sections take the
DEFAULT_CONFIG value — what the agent was actually built with — while an explicit ``null`` stays
None so opting out of a non-None default still rebuilds. Includes the live tool registry
generation: MCP reloads mutate the registry without touching config.yaml."""
out: Dict[str, Any] = {}
cfg = user_config if isinstance(user_config, dict) else {}
for section, key in cls._CACHE_BUSTING_CONFIG_KEYS:
default = cfg_get(DEFAULT_CONFIG, section, key)
section_val = cfg.get(section)
if section == "checkpoints" and isinstance(section_val, bool):
# Legacy ``checkpoints: true``: a live toggle must still rebuild the cached agent.
out[f"{section}.{key}"] = section_val if key == "enabled" else None
elif isinstance(section_val, dict) and key in section_val:
out[f"{section}.{key}"] = section_val[key]
out[f"{section}.{key}"] = section_val if key == "enabled" else default
else:
out[f"{section}.{key}"] = cfg_get(DEFAULT_CONFIG, section, key)
out[f"{section}.{key}"] = cfg_get(cfg, section, key, default=default)
try:
from tools.registry import registry
out["tools.registry_generation"] = getattr(registry, "_generation", None)