In auto mode any extension error fell through to headless Playwright, so
a slow page in the user's own browser came back as Playwright's missing
executable. A connected browser's failure is now the answer; Playwright
stands in only when no browser is on the router. hanzo-tools-browser
0.5.16.
The served document moved past the one this projection was generated
from, so the client lane's check failed every release. uv.lock follows
hanzo-tools-browser onto zapd.
The client lane checks the committed client against the document
api.hanzo.ai serves now, not against the ref .spec-lock pins. Cloud
v1.833.257 (2774987c) went live after 8.5.163 was cut and rewrote the
POST /v1/decisions description (cad76e1a0: Jev by OpenRouter's vendor
ids), so the served document moved from 296b1f84 to 783f66a3 and every
push since has failed the check on ai_api.py's docstring. The drift
reproduces identically at e34ab7e1; nothing in this tree caused it.
This is the lane's own move, done by hand: .spec-lock names the served
revision and digest, the generator reruns over those bytes, uv.lock
takes what `uv run` wrote, and the version takes the next patch.
v8.5.160 regenerated the client and its release run passed the client check,
then stopped at declared-imports: the step called bare `python`, the runner has
none on its PATH, and exit 127 from a step that is report only ended the run
before anything was published. It now runs through uv like the three steps
beside it. Verified by running the whole test: block with no python on PATH.
Co-authored-by: Hanzo Dev <[email protected]>
The committed client had fallen behind the API it projects: 116 modules the
document now names were missing, 13 it no longer names were still here, and
30 had moved. The release lane refuses to publish a projection that does not
match the document, so v8.5.158 and v8.5.159 were tagged and never reached
the index.
Regenerated from the document production serves (sha256 aa1b79d0797704608e25a3898adb2ca69fec82a03f74c09671c372b63066cafe),
with the driver at hanzoai/openapi@88ea26b — the same inputs the lane reads,
and the same +116 -13 ~30 it reported. The repo's own gate ran over exactly
these bytes: 121 api and 2675 model modules import, no class declares a field
twice across 2804 modules, and every example flow resolves its method names.
Co-authored-by: Hanzo Dev <[email protected]>
The hanzo-tools-core suite imports ten sibling tool distributions and
asserts an exact TOOLS count, but they were only ever named in
[tool.uv.sources]. A source resolves a package; it does not make anything
require one, so `uv sync --dev` uninstalled all ten and left the suite at
22 failed / 2 passed. Naming them in the dev dependency-group restores
24 passed, 12 skipped from a clean sync.
pkg/hanzo-dev-py never existed — the directory is pkg/hanzo-dev — so the
eight excludes and workspace members spelling it were inert. mypy.ini is
the config that actually loads, and with the name corrected it stops
type-checking a package it was written to skip (18 errors -> none).
cloud.py cited APIKeyPrefixes as the authority on key prefixes; no such
symbol exists. isAPIKey is the real gate and it admits hk-, sk-, pk-, fw_
and hz_, so NO_KEY was telling callers the wrong two.
(cherry picked from commit b2024662400895e456d4b3811fd286565e4e7109)
GET /v1/models declares a response schema, so the generator emits
AiApi.get_models() -> AiModelList and no longer emits ModelsApi at all.
The example imported the class that folded and failed at import, which is
the whole examples gate.
It reads the typed object now instead of the raw body and its own JSON —
the change its docstring said would arrive the day the schema landed.
288 of hanzoai/ai's 294 operations now declare a response, against 1 before.
GET /v1/models, POST /v1/chat/completions, /v1/embeddings, /v1/messages —
every address a client actually calls — used to reach this client untyped,
because cloud's relay carried an operation's sentence and dropped the shapes
it named. It carries both now.
Fleet-wide the document goes from 69% to 81% of operations declaring what
comes back, which is where the ~208 new models here come from.
The job asked for /v1/kms/orgs/hanzo/secrets/<path>/<key> and parsed
.secret.value. KMS serves GET /v1/kms/secrets/<path>/<key>?env=<env> and
answers {"env","name","value"}, taking the org from the token's own claim,
so every read 404'd and every release reported the credential unseeded —
including hanzo/prod/python-sdk-publish/PYPI_TOKEN, which is there.
Root to 3.2.13, README install line names it. hanzo-research declares its
readme, license and authors, so its page carries them.
uv.lock still carried 3.2.10 after pyproject moved to 3.2.11. A lock that
names a different version than the project it locks is a second answer to a
question with one answer.
Twelve ids came from the document's own old->new map; the rest are generated
method spellings the map does not carry, read off the regenerated client.
Neither set follows a search-and-replace: the document renamed 2014 operations
and 21 of those do not reduce to dropping `_v1_` — /tasks and /meet became
`*_app` and `*_app_assets` when the SPA and the API stopped sharing a name,
and `get_v1_team_transactor_api_v1_statistics` drops only the first, the
second being part of the path.
Checked, not assumed: every `.get_*`/`.post_*` an example calls resolves
against the 7519 methods the client exposes.
The ai door composes, so hanzoai/ai's own contracts reach this client for the
first time: 101 new model modules, 93 write operations that took an untyped bag
now take a declared body, and the fleet document types 1428 of its 2463
operations. 2624 generated modules import clean.
The document types 1495 of its 2459 operations, up from 1242. 87 new model
modules carry the response shapes ai, eval, functions, domain, experiments,
security and benchmark now declare, so those calls return a typed object
instead of a dict. 2524 generated modules import clean.
.spec-lock moves from v1.801.497 to @ffbc86064, which is v1.801.498.
`${OPENAPI:?…}` only prints its word when the variable is unset, but bash
PARSES that word either way, and inside it a lone `'` opens a quote that never
closes: `unexpected EOF while looking for matching '`, at line 23, with OPENAPI
set and the branch not taken. The regeneration died on a message about how to
supply a value it already had.
One regenerated file. o11y.GettableAgentCheckIn declares eight properties and
this client had six: `integration_config`/`integrationConfig` and
`removed_at`/`removedAt` each snake_case to one attribute, so the second
shadowed the first and the survivor kept the camel alias.
That is not cosmetic. The snake_case spellings exist because hanzoai/o11y
publishes them so older AWS agents keep working, and this client read such an
agent's value and then threw it away without raising: from_dict with
{"removed_at": 2020, "removedAt": 2030} returned 2030, and
to_dict()["removed_at"] was None. `to_dict` also wrote one value under both
keys, under two different declared types.
The mapping lives in hanzoai/openapi sdks.yaml, where this client's invocation
is declared; nothing here is hand-edited. Eight fields now, both wire names
carried as aliases, and each value round-trips under its own key. Gate unchanged:
182 api and 2172 model modules import, pytest 6 passed with the same
pre-existing test_zap_transport error.
Co-authored-by: Hanzo Dev <[email protected]>
pkg/hanzoai/cloud goes +2186 -2126 ~175: 1700 paths / 2354 operations / 2186
schemas, 182 api modules and 2172 model modules, against the 239/1116 it carried
from hanzo.yaml. The document is hanzoai/cloud's own emission now, pinned in a
new .spec-lock by commit and sha256, and generate.py reaches it by value —
--skip-validate-spec means the 1012 missing-`responses` errors no longer write
zero files, so a client can be cut from the authority instead of a projection of
it.
Two renamings come with that, and both are the fix rather than the damage. IAM's
types are namespace-qualified (iam.Role, iam.Application, 95 of them) because a
bare `Role` was two unrelated shapes wearing one name. And the <svc>_ prefix is
gone from every operationId, so every generated method lost it.
The prefix is what broke the examples, and the gate saw only two thirds of it.
Four flows failed on their imports; `money` and `tools` PASSED while every call
in them named a method that no longer existed — an import resolves the names in
the `from … import` line and a method is looked up at call time. All five flows
now name operations that exist, checked by resolving each one as an attribute,
and hanzo.yml records that ceiling so the next reader does not trust the gate
for more than it says.
`chat` is removed, which is a measurement and not a preference: cloud declares
POST /v1/chat/completions with no requestBody and no responses at all, so the
generated method takes no body and returns None — the one call a chat example
exists to make cannot be expressed. Inventing the type, or hand-rolling the HTTP
inside a generated client, is the drift these SDKs exist to prevent; js-sdk
dropped its own chat flow at 2.0.7 for exactly this. It returns the release
cloud gives that route a body.
Two smoke assertions were already red before this regeneration and are now true
again: they pinned AIApi/APIKeysApi/MCPApi and AdminApi.plugin_admin_*, names
from the retired lineage. The surface is all still there under AiApi/KeysApi/
McpApi and AdminApi.admin_plugins.
tests/test_zap_transport.py still errors, exactly as it did before: it imports
`Hanzo` from hanzoai, which the hand-written package does not define. That is
not this document's business and is untouched.
Minor rather than patch: every generated method changed name.
Co-authored-by: Hanzo Dev <[email protected]>
Picked up by running the test suite; the lock had drifted behind the workspace
member's own version. No dependency changed.
Co-authored-by: Hanzo Dev <[email protected]>
Regenerated pkg/hanzoai/cloud from hanzo.yaml. Consumed: cloud 8143fc0e,
openapi 2861089 (was f581a0e when 3.1.2 was cut).
openapi 3300cda took {org} out of the KMS secrets contract — the org is read from
the token now — and 3.1.2 shipped from before it, so its KMS methods addressed a
path the server no longer serves:
/v1/kms/orgs/{org}/secrets -> /v1/kms/secrets
/v1/kms/orgs/{org}/secrets/{rest} -> /v1/kms/secrets/{rest}
kms_get_v1_kms_orgs_org_secrets -> kms_get_v1_kms_secrets
kms_post_v1_kms_orgs_org_secrets -> kms_post_v1_kms_secrets
Five request/response models renamed with them. Nothing else in the 1885-path
surface moved: 5 models added, 5 removed, 6 files changed.
3.1.2 never reached PyPI (the tag cannot get to git.hanzo.ai — sync-from-github
fast-forwards main only, never tags), so this is fix-forward, not a replacement.
PyPI still serves 3.1.1; 3.1.2 stays a tag.
The upstream tag-casing collision came back exactly as LLM.md said it would: the
regen rmtree'd the tree and `import hanzoai.cloud` raised ImportError again on
AiApi/ApiKeysApi/McpApi. Stripped the same 9 dead lines. It will return on every
regen until one tag spelling per service lands in the per-service specs — that
also recovers the 127 of 411 operations those 23 colliding groups still drop.
No test pins the KMS route: asserting spec content here would make this repo a
second source of truth for routes and fight the pull-only contract. test_smoke
pins structure instead — import, version, surface breadth. 6 passed.
Version 3.1.2 -> 3.1.3, patch only.
Co-authored-by: Hanzo Dev <[email protected]>
pkg/hanzoai/cloud/ (2163 files) has existed on disk untracked and never shipped.
This commits it, so the operator surface cloud already serves is finally callable:
AdminApi.plugin_admin_plugins / _enable_plugin / _disable_plugin / _reload_plugin
Generated by hanzoai/openapi `generate.py python` from hanzo.yaml (1885 paths,
69 merged per-service specs). Consumed: cloud 8143fc0e, openapi f581a0e.
One driver, so delete the second one. scripts/generate.sh fetched the spec itself
and then did `rm -rf pkg/hanzoai` + copied generator output over it — which would
have deleted the hand-written config/mcp/protocols/session/zap/api_response
modules AND the new cloud/ tree. Nothing referenced it. hanzoai/openapi's
generate.py + sdks.yaml is the only way now; LLM.md records the pipeline.
`import hanzoai.cloud` raised ImportError as generated. hanzo.yaml has 23 tag
groups differing only by case; openapi-generator maps both spellings to one
module, and for AI/ai, API Keys/api-keys and MCP/mcp it then emits imports for
classes it never wrote (AiApi vs AIApi). Stripped those 9 dead lines. The same
collision silently drops 127 of the 411 operations in those groups — that one is
upstream and only a single tag spelling per service fixes it; noted in LLM.md.
Version: 3.1.1 -> 3.1.2, patch only. pkg/hanzoai/__init__.py said 1.0.0 (the
generator default) — now resolved from the installed distribution, same pattern
as hanzo_cli/hanzo_iam in f453dae8. uv.lock refreshed to match committed pkg
versions. test_smoke.py locks the cloud import, the four plugin ops, and that
__version__ equals the distribution: 6 passed.
Co-authored-by: Hanzo Dev <[email protected]>
The fork moved its API off /api to /v1, so every call built against
${{ github.server_url }}/api/v1/... now 404s. Verified live with a control:
/v1/version 200, /api/v1/version 404, a nonsense path 404.
This is the build-dispatch in sync-from-github, so a fast-forward from GitHub
was landing commits and then silently failing to trigger the build.