Skip to content

fix(cli): set User-Agent on /v1/models probe (Cloudflare 1010)#12906

Closed
farion1231 wants to merge 1 commit into
NousResearch:mainfrom
farion1231:fix/probe-models-cloudflare-ua
Closed

fix(cli): set User-Agent on /v1/models probe (Cloudflare 1010)#12906
farion1231 wants to merge 1 commit into
NousResearch:mainfrom
farion1231:fix/probe-models-cloudflare-ua

Conversation

@farion1231

Copy link
Copy Markdown
Contributor

Summary

probe_api_models (in hermes_cli/models.py) sends requests with Python's
default Python-urllib/3.x User-Agent. Custom Claude proxies fronted by
Cloudflare with Browser Integrity Check enabled reject that signature with
HTTP 403 error code: 1010. Because the function wraps the call in a
blanket except Exception: continue, the failure silently degrades to
{"models": None}, which surfaces via validate_requested_model as the
misleading:

✗ Could not reach the custom:<name> API to validate `<model>`.
  If the service isn't down, this model may not be valid.

— even though the endpoint is reachable and the model is in its listing.

Fix

Advertise the probe as hermes-cli/<version> so Cloudflare treats it as a
first-party client. Mirrors the pattern already used in
agent/gemini_native_adapter.py (hermes-agent (gemini-native)) and
agent/anthropic_adapter.py (claude-cli/<version> (external, cli)).

One-line change in probe_api_models; version comes from
hermes_cli.__version__ (already exported).

Reproduction

Before:

python3 -c "
import urllib.request
req = urllib.request.Request(
    'https://www.packyapi.com/v1/models',
    headers={'Authorization': 'Bearer sk-...'})
urllib.request.urlopen(req).read()
"
# urllib.error.HTTPError: HTTP Error 403: Forbidden
# body: b'error code: 1010'

With any non-urllib UA (Mozilla, curl, reqwest — I tested all three) the
same request returns 200 with the OpenAI-compatible models listing.

After the fix, /model claude-opus-4-7 --provider=custom:packy-cc (or
whichever slug the user configured) succeeds end-to-end.

Custom Claude proxies fronted by Cloudflare with Browser Integrity Check
enabled (e.g. `packyapi.com`) reject requests with the default
`Python-urllib/*` signature, returning HTTP 403 "error code: 1010".
`probe_api_models` swallowed that in its blanket `except Exception:
continue`, so `validate_requested_model` returned the misleading
"Could not reach the <provider> API to validate `<model>`" error even
though the endpoint is reachable and lists the requested model.

Advertise the probe request as `hermes-cli/<version>` so Cloudflare
treats it as a first-party client. This mirrors the pattern already used
by `agent/gemini_native_adapter.py` and `agent/anthropic_adapter.py`,
which set a descriptive UA for the same reason.

Reproduction (pre-fix):

    python3 -c "
    import urllib.request
    req = urllib.request.Request(
        'https://www.packyapi.com/v1/models',
        headers={'Authorization': 'Bearer sk-...'})
    urllib.request.urlopen(req).read()
    "
    urllib.error.HTTPError: HTTP Error 403: Forbidden
    (body: b'error code: 1010')

Any non-urllib UA (Mozilla, curl, reqwest) returns 200 with the
OpenAI-compatible models listing.

Tested on macOS (Python 3.11). No cross-platform concerns — the change
is a single header addition to an existing `urllib.request.Request`.
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #12999 (#12999). Your commit was cherry-picked onto current main with your authorship preserved in git log. Thanks @farion1231!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants