Instructions to use Wellz1000/hermes-2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- HERMES
How to use Wellz1000/hermes-2 with HERMES:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
File size: 10,460 Bytes
34c3ee8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | """Codex model discovery from API, local cache, and config."""
from __future__ import annotations
import base64
import json
import logging
from pathlib import Path
from typing import List, Optional
import os
logger = logging.getLogger(__name__)
DEFAULT_CODEX_MODELS: List[str] = [
# GPT-5.6 series (Sol/Terra/Luna + -pro high-effort modes) — GA 2026-07-09
# (previewed 2026-06-26).
"gpt-5.6-sol",
"gpt-5.6-sol-pro",
"gpt-5.6-terra",
"gpt-5.6-terra-pro",
"gpt-5.6-luna",
"gpt-5.6-luna-pro",
"gpt-5.5",
"gpt-5.4-mini",
"gpt-5.4",
"gpt-5.3-codex",
# gpt-5.3-codex-spark is in research preview and is exposed *only* via
# the Codex CLI / OAuth backend (chatgpt.com/backend-api/codex/models)
# for ChatGPT Pro subscribers. It is NOT available in the public OpenAI
# API, so it intentionally stays out of the "openai" provider catalog
# in hermes_cli/models.py — only the openai-codex (OAuth) provider
# surfaces it. The Codex backend reports ``supported_in_api: false`` for
# this slug; that flag describes API availability, not Codex backend
# availability, so the fetch/cache code paths below intentionally do
# not filter on it. PR #12994 removed this entry on the assumption it
# was unsupported — that was wrong; restored here. Keep it in the
# curated fallback so Pro users still see Spark in `/model` when live
# discovery is unavailable (offline first run, transient API failure).
"gpt-5.3-codex-spark",
# NOTE: gpt-5.2-codex / gpt-5.1-codex-max / gpt-5.1-codex-mini were
# previously listed here but the chatgpt.com Codex backend returns
# HTTP 400 "The '<model>' model is not supported when using Codex with
# a ChatGPT account." for all three on every ChatGPT Pro account we've
# tested (verified live 2026-05-27). Keeping them in the fallback list
# leaked dead slugs into /model when live discovery was unavailable
# (transient API failure, first-run before refresh) and surfaced HTTP 400
# crashes on selection. The Codex CLI public catalog still references
# these slugs, which is why they survived previously — but those entries
# describe the public OpenAI API, not the OAuth-backed Codex backend
# Hermes uses. Removed here. If OpenAI re-enables them on Codex backend,
# live discovery will pick them up automatically via _fetch_models_from_api.
]
_FORWARD_COMPAT_TEMPLATE_MODELS: List[tuple[str, tuple[str, ...]]] = [
("gpt-5.6-sol", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-sol-pro", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-terra", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-terra-pro", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-luna", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-luna-pro", ("gpt-5.5", "gpt-5.4")),
("gpt-5.5", ("gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex")),
("gpt-5.4-mini", ("gpt-5.3-codex",)),
("gpt-5.4", ("gpt-5.3-codex",)),
# Surface Spark whenever any compatible Codex template is present so
# accounts hitting the live endpoint with an older lineup still see
# Spark in the picker. Backend gates real availability by ChatGPT Pro
# entitlement; Hermes does not.
("gpt-5.3-codex-spark", ("gpt-5.3-codex",)),
]
def _add_forward_compat_models(model_ids: List[str]) -> List[str]:
"""Add Clawdbot-style synthetic forward-compat Codex models.
If a newer Codex slug isn't returned by live discovery, surface it when an
older compatible template model is present. This mirrors Clawdbot's
synthetic catalog / forward-compat behavior for GPT-5 Codex variants.
"""
ordered: List[str] = []
seen: set[str] = set()
for model_id in model_ids:
if model_id not in seen:
ordered.append(model_id)
seen.add(model_id)
for synthetic_model, template_models in _FORWARD_COMPAT_TEMPLATE_MODELS:
if synthetic_model in seen:
continue
if any(template in seen for template in template_models):
ordered.append(synthetic_model)
seen.add(synthetic_model)
return ordered
def _extract_chatgpt_account_id(access_token: str) -> Optional[str]:
"""Best-effort extraction of ``chatgpt_account_id`` from the OAuth JWT.
The Codex backend requires the ``ChatGPT-Account-Id`` header for the
per-account catalog. Without it, ``GET /backend-api/codex/models``
returns ``{"models":[]}`` (HTTP 200) — which masquerades as "no
models available" and silently degrades the picker to the curated
fallback list. The request-side path in ``auxiliary_client.py``
already extracts the same claim; this mirrors that logic here so the
probe sees the same catalog the request path will actually use.
Returns ``None`` on any parse error — the probe then degrades
gracefully to the unauthenticated fallback list instead of crashing.
"""
try:
parts = access_token.split(".")
if len(parts) < 2:
return None
payload_b64 = parts[1] + "=" * (-len(parts[1]) % 4)
claims = json.loads(base64.urlsafe_b64decode(payload_b64))
acct_id = (
claims.get("https://api.openai.com/auth", {}).get("chatgpt_account_id")
if isinstance(claims, dict)
else None
)
return acct_id if isinstance(acct_id, str) and acct_id else None
except Exception:
return None
def _fetch_models_from_api(access_token: str) -> List[str]:
"""Fetch available models from the Codex API. Returns visible models sorted by priority."""
try:
import httpx
headers = {"Authorization": f"Bearer {access_token}"}
acct_id = _extract_chatgpt_account_id(access_token)
if acct_id:
headers["ChatGPT-Account-Id"] = acct_id
resp = httpx.get(
"https://chatgpt.com/backend-api/codex/models?client_version=1.0.0",
headers=headers,
timeout=10,
)
if resp.status_code != 200:
return []
data = resp.json()
entries = data.get("models", []) if isinstance(data, dict) else []
except Exception as exc:
logger.debug("Failed to fetch Codex models from API: %s", exc)
return []
sortable = []
for item in entries:
if not isinstance(item, dict):
continue
slug = item.get("slug")
if not isinstance(slug, str) or not slug.strip():
continue
slug = slug.strip()
# Codex CLI's catalog uses ``supported_in_api`` for the public OpenAI
# API, not for the OAuth-backed Codex backend that this provider uses.
# Some valid Codex CLI models (for example gpt-5.3-codex-spark) are
# marked false here but are still accepted by the Codex route.
visibility = item.get("visibility", "")
if isinstance(visibility, str) and visibility.strip().lower() in {"hide", "hidden"}:
continue
priority = item.get("priority")
rank = int(priority) if isinstance(priority, (int, float)) else 10_000
sortable.append((rank, slug))
sortable.sort(key=lambda x: (x[0], x[1]))
return _add_forward_compat_models([slug for _, slug in sortable])
def _read_default_model(codex_home: Path) -> Optional[str]:
config_path = codex_home / "config.toml"
if not config_path.exists():
return None
try:
import tomllib
except Exception:
return None
try:
payload = tomllib.loads(config_path.read_text(encoding="utf-8"))
except Exception:
return None
model = payload.get("model") if isinstance(payload, dict) else None
if isinstance(model, str) and model.strip():
return model.strip()
return None
def _read_cache_models(codex_home: Path) -> List[str]:
cache_path = codex_home / "models_cache.json"
if not cache_path.exists():
return []
try:
raw = json.loads(cache_path.read_text(encoding="utf-8"))
except Exception:
return []
entries = raw.get("models") if isinstance(raw, dict) else None
sortable = []
if isinstance(entries, list):
for item in entries:
if not isinstance(item, dict):
continue
slug = item.get("slug")
if not isinstance(slug, str) or not slug.strip():
continue
slug = slug.strip()
# Do not filter on ``supported_in_api`` here. It describes the
# public OpenAI API, while Hermes openai-codex talks to the same
# OAuth-backed Codex backend as Codex CLI.
visibility = item.get("visibility")
if isinstance(visibility, str) and visibility.strip().lower() in {"hide", "hidden"}:
continue
priority = item.get("priority")
rank = int(priority) if isinstance(priority, (int, float)) else 10_000
sortable.append((rank, slug))
sortable.sort(key=lambda item: (item[0], item[1]))
deduped: List[str] = []
for _, slug in sortable:
if slug not in deduped:
deduped.append(slug)
return deduped
def get_codex_model_ids(access_token: Optional[str] = None) -> List[str]:
"""Return available Codex model IDs, trying API first, then local sources.
Resolution order: API (live, if token provided) > config.toml default >
local cache > hardcoded defaults.
"""
codex_home_str = os.getenv("CODEX_HOME", "").strip() or str(Path.home() / ".codex")
codex_home = Path(codex_home_str).expanduser()
ordered: List[str] = []
# Try live API if we have a token
if access_token:
api_models = _fetch_models_from_api(access_token)
if api_models:
return _add_forward_compat_models(api_models)
# Fall back to local sources
default_model = _read_default_model(codex_home)
if default_model:
ordered.append(default_model)
for model_id in _read_cache_models(codex_home):
if model_id not in ordered:
ordered.append(model_id)
for model_id in DEFAULT_CODEX_MODELS:
if model_id not in ordered:
ordered.append(model_id)
return _add_forward_compat_models(ordered)
|