mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +00:00
The remote model catalog (website/static/api/model-catalog.json) now labels exactly one entry per provider block with "default": true — z-ai/glm-5.2 for both OpenRouter and Nous Portal. That labeled entry is the model Hermes silently lands on when the user never picked one, and it can be rotated by editing the manifest alone: no release needed. - model_catalog.py: get_default_model_from_cache() reads the label from the in-process/disk cache only — never triggers a network fetch, so hot resolution paths (agent build, gateway session setup) stay network-free. - models.py: get_preferred_silent_default_model() resolves catalog label first, PREFERRED_SILENT_DEFAULT_MODEL constant second (offline/fresh install). _PROVIDER_SILENT_DEFAULT_OVERRIDES dict replaced by _SILENT_DEFAULT_PROVIDERS routing through the shared resolver. fetch_openrouter_models() preserves the "default" badge through live /v1/models refreshes so the picker shows it. - scripts/build_model_catalog.py: generator emits the default label so regeneration can't drop it. - website/docs/reference/model-catalog.md: schema documents the new field. - Salvaged from PR #61141 (@HumphreySun98): bare-provider /model switches (/model nous) route through the cost-safe default instead of curated entry [0]. - tests: catalog-label precedence, constant fallback, stale-label fallback, cache-only (no network) guarantee, and a shipped-manifest contract test pinning the labeled entry to PREFERRED_SILENT_DEFAULT_MODEL. E2E (temp HERMES_HOME): fresh-install constant fallback, shipped-manifest label read, release-free rotation (relabeled cache -> new default across models.py, tui_gateway, and gateway empty-model paths) all verified.
106 lines
4.6 KiB
Markdown
106 lines
4.6 KiB
Markdown
---
|
|
sidebar_position: 11
|
|
title: Model Catalog
|
|
description: Remotely-hosted manifest driving curated model picker lists for OpenRouter and Nous Portal.
|
|
---
|
|
|
|
# Model Catalog
|
|
|
|
Hermes fetches curated model lists for **OpenRouter** and **Nous Portal** from a JSON manifest hosted alongside the docs site. This lets maintainers update picker lists without shipping a new `hermes-agent` release.
|
|
|
|
When the manifest is unreachable (offline, network blocked, hosting failure), Hermes silently falls back to the in-repo snapshot that ships with the CLI. The manifest never breaks the picker — worst case you see whatever list was bundled with your installed version.
|
|
|
|
## Live manifest URL
|
|
|
|
```
|
|
https://hermes-agent.nousresearch.com/docs/api/model-catalog.json
|
|
```
|
|
|
|
Published on every merge to `main` via the existing `deploy-site.yml` GitHub Pages pipeline. The source of truth lives in the repo at `website/static/api/model-catalog.json`.
|
|
|
|
## Schema
|
|
|
|
```json
|
|
{
|
|
"version": 1,
|
|
"updated_at": "2026-04-25T22:00:00Z",
|
|
"metadata": {},
|
|
"providers": {
|
|
"openrouter": {
|
|
"metadata": {},
|
|
"models": [
|
|
{"id": "z-ai/glm-5.2", "description": "default", "default": true},
|
|
{"id": "moonshotai/kimi-k2.6", "description": "recommended", "metadata": {}},
|
|
{"id": "openai/gpt-5.4", "description": ""}
|
|
]
|
|
},
|
|
"nous": {
|
|
"metadata": {},
|
|
"models": [
|
|
{"id": "z-ai/glm-5.2", "default": true},
|
|
{"id": "anthropic/claude-opus-4.7"},
|
|
{"id": "moonshotai/kimi-k2.6"}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Field notes:
|
|
|
|
- **`version`** — integer schema version. Future schemas bump this; Hermes refuses manifests with versions it doesn't understand and falls back to the hardcoded snapshot.
|
|
- **`metadata`** — free-form dict at the manifest, provider, and model level. Any keys. Hermes ignores unknown fields, so you can annotate entries (`"tier": "paid"`, `"tags": [...]`, etc.) without coordinating a schema change.
|
|
- **`description`** — OpenRouter-only. Drives picker badge text (`"recommended"`, `"free"`, `"default"`, or empty). Nous Portal doesn't use this — free-tier gating is determined live from the Portal's pricing endpoint.
|
|
- **`default`** — exactly one entry per provider may carry `"default": true`. That model is the **silent default**: what Hermes lands on when the user never selected a model (GUI onboarding confirm card, `provider` configured with no `model`, empty `model.default`). Read cache-only at runtime (`get_default_model_from_cache`) so hot resolution paths never hit the network; when no cached manifest exists, Hermes falls back to the in-repo `PREFERRED_SILENT_DEFAULT_MODEL` constant, which must match the labeled entry. This lets maintainers rotate the silent default without shipping a release. It is deliberately a capable low-cost model, never the priciest flagship.
|
|
- **Pricing and context length** are NOT in the manifest. Those come from live provider APIs (`/v1/models` endpoints, models.dev) at fetch time.
|
|
|
|
## Fetch behavior
|
|
|
|
| When | What happens |
|
|
|---|---|
|
|
| `/model` or `hermes model` | Fetches if disk cache is stale, else uses cache |
|
|
| Disk cache fresh (< TTL) | No network hit |
|
|
| Network failure with cache | Silent fallback to cache, one log line |
|
|
| Network failure, no cache | Silent fallback to in-repo snapshot |
|
|
| Manifest fails schema validation | Treated as unreachable |
|
|
|
|
Cache location: `~/.hermes/cache/model_catalog.json`.
|
|
|
|
## Config
|
|
|
|
```yaml
|
|
model_catalog:
|
|
enabled: true
|
|
url: https://hermes-agent.nousresearch.com/docs/api/model-catalog.json
|
|
ttl_hours: 1
|
|
providers: {}
|
|
```
|
|
|
|
Set `enabled: false` to disable remote fetch entirely and always use the in-repo snapshot.
|
|
|
|
### Per-provider override URLs
|
|
|
|
Third parties can self-host their own curation list using the same schema. Point a provider at a custom URL:
|
|
|
|
```yaml
|
|
model_catalog:
|
|
providers:
|
|
openrouter:
|
|
url: https://example.com/my-openrouter-curation.json
|
|
```
|
|
|
|
The overriding manifest only needs to populate the provider block(s) it cares about. Other providers continue to resolve against the master URL.
|
|
|
|
## Updating the manifest
|
|
|
|
Maintainers:
|
|
|
|
```bash
|
|
# Re-generate from the in-repo hardcoded lists (keeps manifest in sync after
|
|
# editing OPENROUTER_MODELS or _PROVIDER_MODELS["nous"] in hermes_cli/models.py).
|
|
python scripts/build_model_catalog.py
|
|
```
|
|
|
|
Then PR the resulting change to `website/static/api/model-catalog.json` to `main`. The docs site auto-deploys on merge and the new manifest is live within a few minutes.
|
|
|
|
You can also hand-edit the JSON directly for fine-grained metadata changes that don't belong in the in-repo snapshot — the generator script is a convenience, not the single source of truth.
|