用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/chchchadzilla/hermes-openrouter-model-picker --skill hermes-openrouter-model-picker命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | hermes-openrouter-model-picker |
| description | Fix missing models in Hermes /model picker. |
| version | 1.0.0 |
| author | ajax |
| license | MIT |
| platforms | ["linux","macos","windows"] |
| metadata | {"hermes":{"tags":["hermes","openrouter","models","model-picker","cache","cron","troubleshooting"],"related_skills":["hermes-agent"]}} |
Two jobs:
/model.Both hinge on one fact most people miss, so read the next section before touching anything.
/model renders the INTERSECTION of two independent caches. A model must be in
BOTH or it silently vanishes. No error, no warning.
| # | File | Role | TTL |
|---|---|---|---|
| 1 | $HERMES_HOME/cache/model_catalog.json | curated manifest — what's allowed | 1h (model_catalog.ttl_hours) |
| 2 | $HERMES_HOME/provider_models_cache.json | live /v1/models ids — what's available | 1h TTL, 7-day stale-serve |
Cache #2 is the trap. In hermes_cli/models.py:
_PROVIDER_MODELS_CACHE_TTL = 3600 # 1h
_PROVIDER_MODELS_STALE_SERVE_MAX = 7 * 24 * 3600 # 7d <-- the trap
An expired entry whose credential fingerprint still matches is served immediately from disk while a daemon thread refetches in the background. That thread only rewrites the disk file — it never updates the list already handed to the picker. Net effect: a newly-released model can be correct in cache #1 and still not render for up to 7 days.
hermes model --refresh does NOT fix this. It clears the picker/catalog caches,
not provider_models_cache.json. This is the single most common wrong turn.
Ordering also comes from cache #1 — the picker preserves manifest order, which is why overriding the manifest is what gives you a chronological list.
Never trust the config; check both caches. Substitute the real model id.
# Step 1 — does it exist upstream at all, and does it support tools?
curl -s https://openrouter.ai/api/v1/models \
| python3 -c "
import json,sys
want='z-ai/glm-5.3'
for m in json.load(sys.stdin)['data']:
if m['id']==want:
sp=m.get('supported_parameters') or []
print(want,'exists | tools:', 'tools' in sp)
break
else: print(want,'NOT on OpenRouter')"
If tools: False, stop — Hermes requires tool calling and deliberately hides such
models (selecting one fails at runtime). That is correct behavior, not a bug.
# Step 2 — which cache is lying? (run from the Hermes install dir, using ITS venv)
cd /usr/local/lib/hermes-agent && ./venv/bin/python -c "
import json, os
from hermes_cli.model_catalog import get_curated_openrouter_models
home=os.environ.get('HERMES_HOME') or os.path.expanduser('~/.hermes')
cur=[m for m,_ in (get_curated_openrouter_models() or [])]
live=json.load(open(f'{home}/provider_models_cache.json')).get('openrouter',{}).get('models',[])
w='z-ai/glm-5.3'
print('in manifest (cache #1):', w in cur)
print('in live cache (cache #2):', w in live)
"
# Step 3 — the actual fix for cache #2
cd /usr/local/lib/hermes-agent && ./venv/bin/python -c "
from hermes_cli import models as M
M.clear_provider_models_cache('openrouter')
ids = M.cached_provider_model_ids('openrouter') # forces live re-fetch
print('rebuilt:', len(ids), 'models')
"
# Step 4 — verify what the picker will ACTUALLY render (end-to-end, not per-cache)
cd /usr/local/lib/hermes-agent && ./venv/bin/python -c "
from hermes_cli import models as M
from hermes_cli.model_catalog import reset_cache
reset_cache(); M._openrouter_catalog_cache=None
lst=M.fetch_openrouter_models(force_refresh=True)
ids=[m for m,_ in lst]
print('entries:',len(lst))
for w in ('z-ai/glm-5.3','google/gemini-3.7-flash'):
print(' ',w,'->','OK' if w in ids else 'MISSING')
"
A live TUI holds warm in-process copies. After fixing on disk, /reload or start a
fresh session.
model_catalog.providers.<provider>.url overrides the curated list for one provider.
Point it at a locally-generated manifest and you control both membership and order.
Override fetches skip the disk cache and re-read on every picker open, so the file
is always as fresh as its last regeneration.
file:// URLs work — they pass _fetch_manifest + schema validation.
Ship scripts/openrouter_chrono_catalog.py (in this skill) and wire it:
cp scripts/openrouter_chrono_catalog.py ~/.hermes/scripts/
python3 ~/.hermes/scripts/openrouter_chrono_catalog.py 100
hermes config set model_catalog.providers.openrouter.url \
"file://$HOME/.hermes/cache/openrouter_chrono.json"
Filtering the script applies (~417 raw → 100):
:batch — async-only endpoints, unusable for interactive chat~alias — floating pointers (~z-ai/glm-latest) that duplicate a concrete idThe script sorts by the created field (every entry has one) and writes a
schema-version-1 manifest. Release date goes in description, though Hermes overwrites
that with its own recommended/free/default badge on some rows — picker-side, unavoidable.
Crucially the script also busts cache #2 whenever top-100 membership changes. Regenerating the manifest alone reintroduces the exact bug in Part 1.
cronjob(action='create', name='openrouter-chrono-catalog-refresh',
schedule='0 */6 * * *', script='openrouter_chrono_catalog.py',
no_agent=True, deliver='local',
prompt='Refresh the chronological OpenRouter model manifest.')
no_agent=True → scheduler runs the script and delivers stdout verbatim. Zero tokens.
hermes model --refresh doesn't clear provider_models_cache.json. Biggest time sink.config.yaml — use hermes config set; a stray indent breaks the live gateway.script takes a bare filename relative to ~/.hermes/scripts/. Absolute paths are
rejected, and argv can't be passed — for flags like --quiet, ship a .sh wrapper./usr/local/lib/hermes-agent/venv/bin/python) for hermes_cli
imports; system python3 lacks the deps. Keep cron scripts dependency-free (stdlib only)
so they run under plain python3 — do JSON surgery instead of importing hermes_cli.&&/heredocs in one terminal call — the parser
blocklist trips on oversized inline payloads. One command per call, or execute_code.provider_models_cache.json; other providers
(xai-oauth, gemini, …) share the file. Verify they survive.fetch_openrouter_models check.tools: False is working as intended — don't "fix" it.fetch_openrouter_models() returns the expected count.:batch / ~alias ids leaked (chronological mode).provider_models_cache.json.ok (cronjob action='run').