diff --git a/hermes_cli/models.py b/hermes_cli/models.py index 1ffede636a1..bc41132f5d5 100644 --- a/hermes_cli/models.py +++ b/hermes_cli/models.py @@ -3702,13 +3702,12 @@ def validate_requested_model( # Static-catalog fallback: when the /models probe was unreachable, # validate against the curated list from provider_model_ids() — same - # pattern as the openai-codex and minimax branches above. This fixes - # /model switches in the gateway for providers like opencode-go and - # opencode-zen whose /models endpoint returns 404 against the HTML - # marketing site. Without this block, validate_requested_model would - # reject every model on such providers, switch_model() would return - # success=False, and the gateway would never write to - # _session_model_overrides. + # pattern as the openai-codex and minimax branches above. This keeps + # /model switches working in the gateway for providers whose /models + # endpoint is temporarily unreachable or returns a non-JSON payload. + # Without this block, validate_requested_model would reject every model + # on such providers, switch_model() would return success=False, and + # the gateway would never write to _session_model_overrides. provider_label = _PROVIDER_LABELS.get(normalized, normalized) try: catalog_models = provider_model_ids(normalized) diff --git a/providers/base.py b/providers/base.py index a9e76823bb2..fa6765d103c 100644 --- a/providers/base.py +++ b/providers/base.py @@ -21,6 +21,20 @@ logger = logging.getLogger(__name__) OMIT_TEMPERATURE = object() +def _profile_user_agent() -> str: + """Return a ``hermes-cli/`` UA string, with a stable fallback. + + Used by ``ProviderProfile.fetch_models`` so the catalog probe is not + served the default ``Python-urllib/`` UA — some providers + (OpenCode Zen, etc.) sit behind a WAF that returns 403 for that. + """ + try: + from hermes_cli import __version__ as _ver # lazy: avoid layer cycle at import time + return f"hermes-cli/{_ver}" + except Exception: + return "hermes-cli" + + @dataclass class ProviderProfile: """Base provider profile — subclass or instantiate with overrides.""" @@ -153,6 +167,10 @@ class ProviderProfile: if api_key: req.add_header("Authorization", f"Bearer {api_key}") req.add_header("Accept", "application/json") + # Some providers (e.g. OpenCode Zen) sit behind a WAF that blocks + # the default ``Python-urllib/`` User-Agent. Set a generic + # hermes-cli UA so the catalog endpoint is reachable. + req.add_header("User-Agent", _profile_user_agent()) for k, v in self.default_headers.items(): req.add_header(k, v) diff --git a/scripts/release.py b/scripts/release.py index 8d2c6c16990..21587212b02 100755 --- a/scripts/release.py +++ b/scripts/release.py @@ -58,6 +58,8 @@ AUTHOR_MAP = { "altriatree@gmail.com": "TruaShamu", "m@mobrienv.dev": "mikeyobrien", "qiyin.zuo@pcitc.com": "qiyin-code", + "mr.aashiz@gmail.com": "aashizpoudel", + "30312689+aashizpoudel@users.noreply.github.com": "aashizpoudel", "oleksii.lisikh@gmail.com": "olisikh", "jeremy@geocaching.com": "outdoorsea", "leone.parise@gmail.com": "leoneparise",