Name the generator we actually run

Our SDKs are generated by openapi-generator on our own CI. The docs said a
hosted third-party service, which we retired: hanzoai/openapi's LLM.md and its
regenerate-sdks.yml both already said so, while its README still called that
service "canonical" and told a reader to fetch an API key for it out of KMS.

Two sources disagreeing is how somebody follows the wrong one, and the wrong one
here sends them looking for a credential that should not exist.

The same claim had spread to what customers and agents read: five pages on
docs.hanzo.ai and six agent skills advertised a vendor we do not use, and
hip-0040 -- the standard for multi-language SDKs -- argued FOR it by name. The
argument survives without the brand, because it was never about the vendor: one
spec beats N hand-written clients. python-sdk's mock script also pulled that
vendor's fork of prism-cli; it takes upstream @stoplight/prism-cli now.

What is deliberately left alone is every occurrence that is not about us: a
filament material in a 3D-printer integration, a browser of that name in three
user-agent parsers, tokenizer vocabulary where the string is a token id, and
citations recording where Mux, Perigon and Stigg publish their own specs.
Renaming any of those breaks something real.
This commit is contained in:
2026-08-13 14:30:19 -07:00
parent 6d5dc78fcb
commit aad145dec0
5 changed files with 109 additions and 8 deletions
+3 -3
View File
@@ -1,4 +1,4 @@
File generated from our OpenAPI spec by Stainless.
Generated from our OpenAPI spec.
This directory can be used to store example files demonstrating usage of this SDK.
It is ignored by Stainless code generation and its content (other than this keep file) won't be touched.
This directory holds example files demonstrating usage of this SDK. Code
generation ignores it, so nothing here is overwritten by a regeneration.
+101
View File
@@ -0,0 +1,101 @@
# hanzo-tasks
Durable activities on the native Hanzo Tasks engine.
The engine is Hanzo's own (`hanzoai/tasks`), reached over JSON at
`api.hanzo.ai/v1/tasks`. It speaks no protobuf and no gRPC, and this package
depends on no workflow runtime — dispatching work and running a worker are both
plain HTTP over `httpx`.
```bash
pip install hanzo-tasks
```
## Dispatch
```python
from hanzo_tasks import Tasks
async with Tasks.from_env() as tasks:
activity = await tasks.dispatch(
"render",
input={"scene": 3},
task_queue="gpu",
heartbeat_timeout="60s",
)
print(activity.id, activity.run_id, activity.status)
```
`from_env()` reads `HANZO_API_KEY`, `HANZO_TASKS_URL` and
`HANZO_TASKS_NAMESPACE`. The org is never named in a request: IAM validates the
bearer token and the edge mints the org from the validated claim, so a caller
cannot reach another tenant's shard by asking to.
## Run a worker
The worker **polls**. It never accepts a push, so it needs no inbound address
and runs behind NAT.
```python
from hanzo_tasks import Tasks, Worker
tasks = Tasks.from_env()
worker = Worker(tasks, task_queue="gpu")
@worker.handler("render")
async def render(activity):
return {"frames": 120}
await worker.run()
```
Return a value to complete the activity; raise to fail it with that cause.
Handlers may be async or plain functions.
## What the engine does, so you don't
These are properties of the engine, not of this client. There is deliberately
no second copy of them here, because a second copy can disagree.
- **A dead worker's work comes back.** The engine reaps expired leases before
every claim, so an activity whose claimant stopped heartbeating returns to
`SCHEDULED` and the next poll picks it up. No client-side timer.
- **Two workers never claim the same activity.** Claims are serialized per
namespace.
- **The lease is the activity's own heartbeat timeout**, else the worker's
`lease_seconds`, else the engine default. `Worker` heartbeats at a third of
the window the server actually granted, so a beat can be missed without
losing the claim.
- **An empty queue is not an error.** It is `204`, and `claim()` returns
`None`.
- **Retries are the engine's.** Pass a `RetryPolicy` to `dispatch()`; the
engine counts attempts and fails the activity when they are exhausted.
## Reading state
```python
page = await tasks.activities(page_size=50)
for activity in page:
print(activity.id, activity.status, activity.attempt)
activity = await tasks.describe(id, run_id)
events, cursor = await tasks.history(id, run_id)
```
## Errors
The engine reports `{"error": ..., "code": <int>}` — `code` is a number here,
not the `status` string the rest of the Hanzo API uses.
| Exception | Meaning |
|---|---|
| `Denied` | 401/403 — no validated principal, or one carrying no org |
| `NotFound` | 404 — no such activity in this namespace |
| `Terminal` | 409 — already completed, failed or canceled |
| `TasksError` | anything else, carrying `.code` |
## License
MIT
@@ -27,7 +27,7 @@ from __future__ import annotations
import re
from typing import Any, Dict, List, Final, Tuple, Union
from functools import lru_cache # noqa: TID251 - not using Stainless SDK
from functools import lru_cache # noqa: TID251 - hand-written package, not the generated client
# Type aliases with full annotations
ASTDict = Dict[str, Any]
+2 -2
View File
@@ -2,8 +2,8 @@
# Regenerate the Hanzo Python client (`hanzoai`) from the unified OpenAPI spec.
#
# The ONE way: hanzoai/openapi `hanzo.yaml` is the single source of truth. The
# `hanzoai` package under pkg/ is generated from it with openapi-generator — no
# Stainless. Other pkg/hanzo-* packages are hand-written and untouched here.
# `hanzoai` package under pkg/ is generated from it with openapi-generator, run
# on our own CI. Other pkg/hanzo-* packages are hand-written and untouched here.
#
# ./scripts/generate.sh # pulls spec from hanzoai/openapi@main
# SPEC=/path/to/hanzo.yaml ./scripts/generate.sh # local spec override
+2 -2
View File
@@ -21,7 +21,7 @@ echo "==> Starting mock server with URL ${URL}"
# Run prism mock on the given spec
if [ "$1" == "--daemon" ]; then
npm exec --package=@stainless-api/[email protected] -- prism mock "$URL" &> .prism.log &
npm exec --package=@stoplight/[email protected] -- prism mock "$URL" &> .prism.log &
# Wait for server to come online
echo -n "Waiting for server"
@@ -37,5 +37,5 @@ if [ "$1" == "--daemon" ]; then
echo
else
npm exec --package=@stainless-api/[email protected] -- prism mock "$URL"
npm exec --package=@stoplight/[email protected] -- prism mock "$URL"
fi