mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
hanzoai/cloud@113cf7d6 declares components.securitySchemes.bearer and applies it document-wide, so regenerating writes a populated Configuration.auth_settings() and auth_settings=['bearer'] into 2498 call sites; ApiClient._apply_auth_params sets Authorization: Bearer <token> from access_token, which was read by nothing before. Four call sites carry an empty list — exactly the operations the document marks security: [] (get_models, get_models_providers, get_commands, get_openapi_json) — so the public routes still go out with no credential. examples/client.py drops the header_name/header_value compensation and passes access_token. examples/models is a new flow on the public catalog: it runs before a reader has a key, which makes the install checkable in one command. Proven on api.hanzo.ai, not by reading: examples.models prints 112 models with no credential; examples.hello returns the caller's keys with a real sk- and 403 "sign in to manage API keys" with a bogus one.
54 lines
2.2 KiB
Python
54 lines
2.2 KiB
Python
"""models — the catalog, with no credential at all.
|
|
|
|
``GET /v1/models`` (operationId ``get_models``): every model the router can
|
|
reach, with its owner and its per-token price.
|
|
|
|
This is the flow that runs before you have a key, and the only one that can. The
|
|
document marks four of its 2479 operations ``security: []`` and this is one of
|
|
them: the catalog is the same for every caller, so the operation takes no
|
|
principal and the generated method sends no ``Authorization`` header. That is
|
|
visible in the generated code — ``_get_models_serialize`` carries an empty
|
|
``_auth_settings``, where all 2498 other call sites carry ``['bearer']``.
|
|
|
|
So this doubles as the install check. If it prints a count, the package imports,
|
|
the host resolves, and the client speaks the API. If it prints a count when you
|
|
expected a refusal, that is not a broken key — this route never looks at one.
|
|
|
|
The payload is read through the generated ``*_without_preload_content`` variant
|
|
because the operation declares no response ``content``: 834 of the document's
|
|
operations model no body, so the typed method returns None. It becomes an
|
|
ordinary typed call the day the schema lands, and nothing else here changes.
|
|
|
|
python -m examples.models
|
|
"""
|
|
|
|
import json
|
|
|
|
from hanzoai.cloud import ModelsApi
|
|
|
|
from examples.client import BASE_URL, public, run
|
|
|
|
|
|
def main() -> None:
|
|
with public() as api:
|
|
response = ModelsApi(api).get_models_without_preload_content()
|
|
body = response.read()
|
|
|
|
# The raw variant does NOT raise on a 4xx — that check is part of the typed
|
|
# deserialization this operation does not have.
|
|
if response.status >= 400:
|
|
raise SystemExit(f"HTTP {response.status}: {body.decode(errors='replace')}")
|
|
|
|
models = json.loads(body).get("data", [])
|
|
print(f"{BASE_URL} serves {len(models)} models, no credential required")
|
|
for model in models[:10]:
|
|
price = (model.get("pricing") or {}).get("input")
|
|
rate = f"${price}/Mtok in" if price is not None else "unpriced"
|
|
print(f" {model['id']} · {model.get('owned_by') or 'unowned'} · {rate}")
|
|
if len(models) > 10:
|
|
print(f" … and {len(models) - 10} more")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run(main)
|