Metadata-Version: 2.3
Name: hanzoai
Version: 8.5.156
Summary: The official Python library for the Hanzo API
Project-URL: Homepage, https://github.com/hanzoai/python-sdk
Project-URL: Repository, https://github.com/hanzoai/python-sdk
Author-email: Hanzo <dev@hanzo.ai>
License: Apache-2.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: OS Independent
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: pydantic<3,>=2.10
Requires-Dist: python-dateutil>=2.8.2
Requires-Dist: typing-extensions<5,>=4.10
Requires-Dist: urllib3<3,>=2.1.0
Provides-Extra: llm
Requires-Dist: hanzo-llm>=1.0.0; extra == 'llm'
Provides-Extra: zap
Requires-Dist: hanzo-zap>=0.7.0; extra == 'zap'
Requires-Dist: httpx>=0.27.0; extra == 'zap'
Description-Content-Type: text/markdown

# Hanzo Python SDK

`hanzoai` is the Python client for the Hanzo API, generated from the API's own
OpenAPI document. Every `/v1` route is in it, and the names it exposes are the
document's operation ids. [`.spec-lock`](https://github.com/hanzoai/python-sdk/tree/main/.spec-lock) names the commit and sha256
of the document this tree was cut from.

[![PyPI](https://img.shields.io/pypi/v/hanzoai.svg)](https://pypi.org/project/hanzoai/)
[![Python](https://img.shields.io/pypi/pyversions/hanzoai.svg)](https://pypi.org/project/hanzoai/)

## Install

```bash
pip install hanzoai
```

Check the install without a key — `GET /v1/models` is public:

```bash
python -m examples.models
```

```
https://api.hanzo.ai serves 112 models, no credential required
  all-mini-lm-l6-v2 · do-ai · $0.02/Mtok in
  anthropic-claude-opus-5 · do-ai · $1/Mtok in
  …
```

## Quickstart

```python
import os
from hanzoai.cloud import ApiClient, Configuration, KeysApi

client = ApiClient(Configuration(
    host="https://api.hanzo.ai",
    access_token=os.environ["HANZO_API_KEY"],
))

with client as api:
    for key in KeysApi(api).get_keys().keys or []:
        print(key.prefix, key.type, key.created_at)
```

Every route follows that shape: one `*Api` class per tag, one method per
operation, typed models in and out.

## Auth

`access_token` is the whole configuration — it becomes
`Authorization: Bearer <token>` on every operation that asks for a credential.

Four operations do not: `GET /v1/models`, `GET /v1/models/providers`,
`GET /v1/commands`, `GET /v1/openapi.json`. They send no credential, which is why
`examples/models` runs before you have a key.

Keys come from [cloud.hanzo.ai](https://cloud.hanzo.ai) or `hanzo login` in two
shapes, and only one of them works here. Use an `sk-`: it carries a principal,
which every credentialled call needs. A `pk-` is publishable — safe in a browser
bundle because it names an org and authenticates nobody — so cloud refuses it at
the identity boundary.

No generated code reads the environment, so no variable you export reaches a
request on its own. (The hand-written `hanzoai.zap` and `hanzoai.config` read
`HANZO_ZAP_ENDPOINT` and `HANZO_CONFIG_HOME`; neither is a credential.)
[`examples/client.py`](https://github.com/hanzoai/python-sdk/tree/main/examples/client.py) is where `HANZO_API_KEY` and
`HANZO_BASE_URL` get resolved, for all six flows.

## Examples

`examples/` carries one directory per flow. Each is a whole path through one part
of the API. CI imports all six and resolves every method name they call against
the client.

| flow | what it does | routes | key |
|---|---|---|---|
| [`models`](https://github.com/hanzoai/python-sdk/tree/main/examples/models) | the model catalog | `GET /v1/models` | none |
| [`hello`](https://github.com/hanzoai/python-sdk/tree/main/examples/hello) | prove the key works | `GET /v1/keys` | `sk-` |
| [`money`](https://github.com/hanzoai/python-sdk/tree/main/examples/money) | balance + usage | `GET /v1/billing/balance`, `GET /v1/billing/usage` | `sk-` |
| [`store`](https://github.com/hanzoai/python-sdk/tree/main/examples/store) | KV round-trip | `POST /v1/kv`, `GET`/`DELETE /v1/kv/{name}` | `sk-` |
| [`agent`](https://github.com/hanzoai/python-sdk/tree/main/examples/agent) | create, run, read the runs | `POST /v1/agents`, `POST /v1/agents/{ref}/run`, `GET /v1/agents/{ref}/runs` | `sk-` |
| [`tools`](https://github.com/hanzoai/python-sdk/tree/main/examples/tools) | the tool catalog | `GET /v1/tools` | `sk-` |

One command each, from the repo root:

```bash
python -m examples.models                  # no credential

export HANZO_API_KEY=sk-...
python -m examples.hello
```

A real key prints your keys; a bogus one prints
`HTTP 403: {"code":"forbidden","error":"sign in to manage API keys"}`.

There is no `chat` flow: `POST /v1/chat/completions` is declared with no
`requestBody` and no `responses`, so the method takes no arguments and returns
`None`. It comes back the day the document describes the body.

`money` reads its two payloads through the generated
`*_without_preload_content` variant, for the same reason — an operation that
declares no `responses`, or a 2xx carrying no content, models no body to
deserialize.

Reference for the routes themselves: [api.hanzo.ai/docs](https://api.hanzo.ai/docs),
served from the same document — [api.hanzo.ai/v1/openapi.json](https://api.hanzo.ai/v1/openapi.json).

## The rest of the repo

This is a `uv` workspace. `pkg/hanzoai` is the client above; the other packages
are hand-written, ship separately, and mostly carry their own README:

| Package | Install | Purpose |
|---|---|---|
| `pkg/hanzoai` | `hanzoai` | the client above |
| `pkg/hanzo-mcp` | `hanzo-mcp` | Model Context Protocol server |
| `pkg/hanzo-agent` | `hanzo-agent` | agent framework (import path `agents`) |
| `pkg/hanzo-agents` | `hanzo-agents` | agent networks and swarms |
| `pkg/hanzo-memory` | `hanzo-memory` | persistent memory + RAG over SQLite |
| `pkg/hanzo-network` | `hanzo-network` | distributed compute nodes |
| `pkg/hanzo-tools-*` | one each | single-concern tool packages, each registering a `TOOLS` list under the `hanzo.tools` entry point, which is how `hanzo-mcp` finds them |

The `hanzo` **command** is a native binary, not a Python package:
`curl -fsSL https://hanzo.sh | sh`. `pip install hanzo` ships the older Python CLI
under the name `hanzo-py`, so the two never fight over one name on a PATH.

## Development

```bash
git clone https://github.com/hanzoai/python-sdk && cd python-sdk
uv sync --all-packages
uv run pytest tests/ -v
```

`pkg/hanzoai/cloud/` is generated and is never edited by hand — a regeneration
does `rmtree` then `copytree`, so an edit there is gone on the next run. It comes
from [hanzoai/openapi](https://github.com/hanzoai/openapi):

```bash
cd ../openapi && uv run --with pyyaml python3 generate.py python \
  --repo ../python-sdk --spec ../cloud/openapi.yaml
```

A defect in generated code is fixed in the document.

## License

Apache 2.0 — see [LICENSE](https://github.com/hanzoai/python-sdk/tree/main/LICENSE). Report vulnerabilities to security@hanzo.ai
([SECURITY.md](https://github.com/hanzoai/python-sdk/tree/main/SECURITY.md)).

## Hanzo — the Open AI Cloud

[hanzo.ai](https://hanzo.ai) · [docs.hanzo.ai](https://docs.hanzo.ai) ·
same client in other languages:
[TypeScript](https://github.com/hanzoai/js-sdk) ·
[Go](https://github.com/hanzoai/go-sdk) ·
[Java](https://github.com/hanzoai/java-sdk) ·
[Kotlin](https://github.com/hanzoai/kotlin-sdk) ·
[umbrella](https://github.com/hanzoai/sdk)
