mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-09 08:21:50 +00:00
feat(models): seed model-catalog disk cache from checkout on update (#42614)
hermes update pulls the latest repo, so the freshly-pulled website/static/api/model-catalog.json is already the newest catalog. Copy it straight over ~/.hermes/cache/model_catalog.json instead of relying on a network fetch (which can be Vercel bot-gated or hit a Portal hiccup and silently degrade the picker to a stale/short list). Adds seed_cache_from_checkout() in model_catalog.py (read shipped manifest, validate, atomic write via _write_disk_cache, reset in-process cache) and calls it from both update paths in main.py: _cmd_update_impl (git pull) and _update_via_zip (Docker/no-git). Non-fatal on missing/malformed/invalid files — the normal network refresh still applies on next picker open.
This commit is contained in:
parent
c1927d2342
commit
54318c65b0
2 changed files with 57 additions and 0 deletions
|
|
@ -5806,6 +5806,16 @@ def _update_via_zip(args):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
# Seed the model-catalog disk cache from the freshly-unpacked checkout
|
||||
# (same rationale as the git-pull path in _cmd_update_impl). Non-fatal.
|
||||
try:
|
||||
from hermes_cli.model_catalog import seed_cache_from_checkout
|
||||
|
||||
if seed_cache_from_checkout(PROJECT_ROOT):
|
||||
print(" ✓ Model catalog cache refreshed from checkout")
|
||||
except Exception as e:
|
||||
logger.debug("Model catalog seed during zip update failed: %s", e)
|
||||
|
||||
print()
|
||||
print("✓ Update complete!")
|
||||
try:
|
||||
|
|
@ -8365,6 +8375,22 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
print()
|
||||
print("✓ Code updated!")
|
||||
|
||||
# Seed the model-catalog disk cache from the freshly-pulled checkout.
|
||||
# The repo ships the canonical catalog at
|
||||
# website/static/api/model-catalog.json, and `git pull` just made it
|
||||
# current — so copy it straight over ~/.hermes/cache/model_catalog.json
|
||||
# instead of waiting on a network fetch (which can be bot-gated or hit a
|
||||
# Portal hiccup). Keeps the model picker's curated/free lists in sync
|
||||
# with the version the user just installed. Non-fatal on failure: the
|
||||
# normal network refresh still applies on the next picker open.
|
||||
try:
|
||||
from hermes_cli.model_catalog import seed_cache_from_checkout
|
||||
|
||||
if seed_cache_from_checkout(PROJECT_ROOT):
|
||||
print(" ✓ Model catalog cache refreshed from checkout")
|
||||
except Exception as e:
|
||||
logger.debug("Model catalog seed during update failed: %s", e)
|
||||
|
||||
# After git pull, source files on disk are newer than cached Python
|
||||
# modules in this process. Reload hermes_constants so that any lazy
|
||||
# import executed below (skills sync, gateway restart) sees new
|
||||
|
|
|
|||
|
|
@ -356,6 +356,37 @@ def get_curated_nous_models() -> list[str] | None:
|
|||
return out or None
|
||||
|
||||
|
||||
def seed_cache_from_checkout(project_root: "Path | str") -> bool:
|
||||
"""Overwrite the disk cache with the catalog shipped in a local checkout.
|
||||
|
||||
``hermes update`` pulls the latest repo, so the freshly-pulled
|
||||
``website/static/api/model-catalog.json`` IS the newest catalog — no
|
||||
network round-trip needed. Copying it straight over the disk cache keeps
|
||||
the model picker current even when the remote manifest fetch is bot-gated
|
||||
or the Portal hiccups.
|
||||
|
||||
Reads the shipped manifest, validates it against the schema, and writes it
|
||||
to ``~/.hermes/cache/model_catalog.json`` via the same atomic writer the
|
||||
network path uses. Returns ``True`` on success, ``False`` if the file is
|
||||
missing, malformed, or fails validation (caller should treat a ``False``
|
||||
as non-fatal — the network fetch path still applies on the next picker
|
||||
open).
|
||||
"""
|
||||
src = Path(project_root) / "website" / "static" / "api" / "model-catalog.json"
|
||||
try:
|
||||
with open(src, encoding="utf-8") as fh:
|
||||
data = json.load(fh)
|
||||
except (OSError, json.JSONDecodeError) as exc:
|
||||
logger.debug("model catalog seed from checkout skipped (%s): %s", src, exc)
|
||||
return False
|
||||
if not _validate_manifest(data):
|
||||
logger.debug("model catalog seed from checkout skipped: invalid manifest at %s", src)
|
||||
return False
|
||||
_write_disk_cache(data)
|
||||
reset_cache() # drop the in-process copy so the next read picks up the seed
|
||||
return True
|
||||
|
||||
|
||||
def reset_cache() -> None:
|
||||
"""Clear the in-process cache. Used by tests and ``hermes model --refresh``."""
|
||||
global _catalog_cache, _catalog_cache_source_mtime
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue