Commit Graph
846 Commits
Author SHA1 Message Date
zeekay 4dac77fe06 hanzo-train 0.1.1 drives the training wire at /v1/train/clients. 2026-09-28 22:11:20 -07:00
zeekayandHanzo Dev 875469edc7 client: regenerate from hanzo-inc/cloud@20e58292d2 (8.5.162)
Co-authored-by: Hanzo Dev <[email protected]>
v8.5.162
2026-09-29 01:37:51 +00:00
zeekay 0336582777 Pin the CI caller to hanzoai/ci 4b737d1, whose tools checkout fetches a pinned sha. 2026-09-28 18:33:30 -07:00
zeekay 68d560c316 The store and agent examples name the document's ProvisioningProvisionRequest and AgentCreateAgentIn. 2026-09-28 18:33:24 -07:00
zeekayandHanzo Dev d044022152 client: regenerate from hanzo-inc/cloud@8eb2e12e26 (8.5.162)
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-29 01:18:01 +00:00
zeekay 7d85ade686 Pin the CI caller to hanzoai/ci 58fd5da, whose cut pushes to github.com with a GitHub token. 2026-09-28 18:14:06 -07:00
zeekay fb29d854fa The versioned-id fixture asks /v1/decisions only to accept the id, and /v1/systemone to answer with it 2026-09-28 18:10:48 -07:00
zeekay 8102dad40b sdk_jev asks about a March invoice, as the other examples do. 2026-09-28 18:05:58 -07:00
zeekay 169648c43d hanzo_kai.jev lists the decision models of data in Jev's shape, and the conformance fixtures name every reach refusal and pin Kai's versioned id 2026-09-28 17:37:54 -07:00
zeekay 70cb092e67 hanzo-kai's examples are the programs behind every Python page of the Kai docs. 2026-09-28 16:35:51 -07:00
zeekay 15c3a6ea95 Bring hanzo-kai to the frozen decision contract, with the Jev-compatible hanzo_kai.jev and a conformance fixture per rule 2026-09-28 14:57:06 -07:00
zeekay 75771bfe7f Add hanzo-kai, the Python client for Kai decisions 2026-09-28 14:32:02 -07:00
zeekayandHanzo Dev 862f504cb4 LLM.md is the one committed guide; CLAUDE.md, AGENTS.md and GEMINI.md are local links to it
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-24 15:48:10 -07:00
zeekayandHanzo Dev 2e271b5168 Install hanzoai>=8, so an older Python refuses instead of installing 2.1
Hanzo CI/CD / test (linux-amd64) (push) Successful in 2m42s
Hanzo CI/CD / test (linux-arm64) (push) Successful in 5m16s
Hanzo CI/CD / cicd (push) Failing after 2m2s
CI/CD / cicd (push) Failing after 9m50s
hanzoai 8 requires Python 3.12, and PyPI serves 2.1.3 to 3.9-3.11. An
unpinned `pip install hanzoai` there installed the 2.1 client without a word,
and every example here failed on `from hanzoai.cloud import ...`. Every install
line now carries the floor, which pip 21 on Python 3.9 answers with "No
matching distribution found for hanzoai>=8", and the quickstart no longer says
Python 3.9.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 11:11:59 -07:00
zeekayandHanzo Dev 02fbcb91bb Drop the install-from-git detour
Hanzo CI/CD / cicd (push) Failing after 2m5s
CI/CD / cicd (push) Failing after 2m6s
PyPI has shipped Client since 8.5.161, so a new user following the README
was sent to a git install they do not need.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-22 23:04:24 -07:00
zeekayandHanzo Dev 3335b2fa21 hanzoai 8.5.161: the import report runs under the interpreter its siblings fetch
Hanzo CI/CD / cicd (push) Successful in 2m21s
CI/CD / cicd (push) Successful in 2m21s
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]>
v8.5.161
2026-09-18 22:23:29 -07:00
zeekayandHanzo Dev 40cb597c2f client: regenerate from hanzo-inc/cloud@2314af8b90 (8.5.160)
Hanzo CI/CD / cicd (push) Failing after 2m6s
CI/CD / cicd (push) Failing after 2m7s
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]>
v8.5.160
2026-09-18 17:28:47 -07:00
zeekayandHanzo Dev ea1940e3e3 hanzoai 8.5.159
Co-authored-by: Hanzo Dev <[email protected]>
v8.5.159
2026-09-11 13:44:15 -07:00
zeekayandHanzo Dev fb564b4d49 test_smoke follows the tools tag to tool
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 13:44:15 -07:00
zeekayandHanzo Dev a2652a6979 Stop a rate-limited call from sleeping for hours
urllib3 sleeps whatever Retry-After says, clamped at 6 h in 2.7, and retries three times. api.hanzo.ai sends ~23,000 s for an exhausted quota, so one GET held its caller for 18 h. Client sleeps through at most 60 s; past that the answer returns at once, as ApiException with the header for generated operations and as Fault.retry_after for the six.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 13:44:15 -07:00
zeekayandHanzo Dev 321aa75a5c Say what pip installs, and fix two examples that no longer import
pip install hanzoai on 3.12 gets 8.5.156, which has no Client; on 3.9 to
3.11 it gets the 2.1 line, a different client. The README said neither.
It showed KeysApi and MemoryApi, which the generated client does not
have, and mapped hanzo-agent and hanzo-agents to copies here that PyPI
does not publish.

examples/agent and examples/tools imported AgentsApi and ToolsApi, which
the document now names AgentApi and ToolApi. Both flows ran against a
local server after the change. The per-agent runs read is generated
without its ref, so the agent flow reads /v1/agent/runs and keeps its
own rows.

The status table and the Retry-After lines come from runs against a
local server: a capability call is one request, two on a 401; a
generated operation sleeps for Retry-After on 429 or 503 and retries
three times.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 10:47:40 -07:00
zeekayandHanzo Dev e6f6ff34d7 Map the imports no package declares
hanzo-agent 0.1.0 went to PyPI importing numpy and httpx and declaring
neither. In this repo the workspace supplies every sibling, so its own tests
all passed; `pip install hanzo-agent` then failed at import for everybody else.
An outside adopter hit that, gave up on three of our packages, and wrote their
own clients — the most expensive kind of bug we ship, because it is invisible
from inside the tree.

This reports every import across the 64 packages that its own manifest does not
declare. 90 of them.

It does NOT fail, and the reason is a limit of reading rather than leniency:
hanzo-zap imports `zap` and declares `zap-proto`, which provides it;
hanzo-tools-iam imports `mcp` and declares a sibling that depends on it.
Neither is broken and both look identical to a parser. Failing 90 rows on day
one is how a gate gets switched off.

It still earns its place. Relying on a transitive dependency is a break waiting
for the day that sibling drops it, and 90 rows is a map of where that sits.

The authoritative check — install each wheel alone in a clean venv and import
it — belongs in the shared publish lane rather than a copy here, which is the
point dd889c29 already made when it removed this repo's own lane.

The `zap` row was mine: the first run said 92 because the alias table did not
know zap-proto provides it.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 23:04:17 -07:00
zeekayandHanzo Dev ca850e5cc9 Guard the install check against an empty catalogue
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 21:56:10 -07:00
zeekayandHanzo Dev 39bc72bc09 Give the install check a form the wheel carries
The line under `pip install hanzoai` was `python -m examples.models`, and
examples/ is in the sdist only — hatch's wheel target is pkg/hanzoai. So
the first command in the README answered ModuleNotFoundError to everyone
who installed the package the way the line above told them to.

Co-authored-by: Hanzo Dev <[email protected]>
v8.5.158
2026-09-10 21:50:23 -07:00
zeekayandHanzo Dev 30a465e537 Release through the shared lane, not a copy of it
publish-pypi.yml was a per-repo spelling of a rule the whole estate
needs, and it was the estate's only one: a Python repo without a copy
of this file could not publish at all. `pypi:` in hanzo.yml now names
what ships and hanzoai/ci ships it, so the rule has one home.

The hardcoded package list goes with it. A glob over pkg/ cannot fail
to notice a package added beside it, and the tag is matched against
each pyproject's own name rather than against a case list, so all four
tag shapes already in this repo's history resolve to the same
distributions they did before.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 21:44:51 -07:00
zeekayandHanzo Dev 234c2d8cf1 Prefer tgrep where the tree carries an index
Trigram index prunes files a query cannot match: 23ms against ripgrep's 78ms
for an absent symbol, which is most of what a search asks. It loses where many
files match (128ms against 78ms), and with no index it scans everything and is
slower than plain grep — so the index is the condition, not the binary.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 17:24:51 -07:00
zeekayandHanzo Dev 2b0401db54 ci: confirm a push still schedules a run
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 17:24:51 -07:00
zeekayandHanzo Dev 206be715d8 ci: verify the GitHub->forge inbound leg delivers
No file changes: this exercises the ingest path only, so the forge head
must advance to this commit without a build being cut.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 17:24:51 -07:00
zeekayandHanzo Dev 0da7a4185c fix(six): one word, one body, one shape across the three SDKs
Thirteen places where this SDK and the other two answered the same question
differently. Every one is now what the served handler reads, or what HIP-0044
says where the handler is silent.

Where this SDK was already right, the other two moved: search normalizes the
knowledge kind in both directions, `Page.total` stays the server's own count,
and `put` picks its method from the name. Where it was not:

- kb.Import carries what the handler answers. `/v1/knowledge/import` writes
  {format, imported, pages} (knowledge/import.go); this modelled `imported`
  alone, so a caller could not see which pages landed.
- Fact carries the server's three. `GET /v1/graph` serves twelve members
  (graph/typed.go, wireFact) and no other route hands back an assertion's
  content address, so projecting the nine an asserter states made a read lossy
  with nothing to recover it from. `id`, `by` and `knowable` arrive read-only
  and `write()` never sends them.
- graph.extract and graph.ingest take a Source. Both routes bind the same
  {source, subject, text, at} (graph/semantic.go, graphSourceIn), so it is one
  value — and the first positional argument is now the same thing here as it is
  in the other two.
- import_(format, data, project) — the order the contract writes and the other
  two take. It was (export, *, format).
- A body carries what somebody set. `send` dropped None from the query and left
  it in the body, so `search.find` posted {"index": null, "offset": null,
  "project": null} where the other two omit the key: three requests for one
  call, and cloud asked to read a value where there is none. Audit's pageSize
  and p go the same way — the route's own defaults are the same 100 and 1, so
  an unset term is one the route decides identically, and `all` pins the size it
  walks at because it needs to know the page length.
- A write body is field data and nothing else. `url` belongs to a source, and an
  empty title is left out so the doctype names the required field that is
  missing rather than being handed a blank one.
- kb.list takes order and kb.links takes a project. `/v1/framework/{doctype}`
  serves order_by and `/v1/knowledge/graph` serves ?project=.
- policy_denied and entitlement_required do not exist. Neither string appears
  anywhere in hanzoai/cloud, so REFUSED is the two codes it does emit. A 403
  read as denied on an invented code would hand an unauthenticated caller a cure
  for a refusal nobody made.
- One refusal reader, by named fallback: code from `code` else `error`, reason
  from `detail` else `message`, cures from `cure`. The gate's own `reason` —
  "unpaid", "unresolved" — names the admit leg that failed rather than
  explaining anything, so it is dropped, and `title` is not a refusal member.
- Money counts minor units, not cents: hundredths for USD, whole yen for JPY,
  thousandths for KWD.
- Balance.reserved, not held. The wire says `holds`; `held` is an arm.
- Vocabulary.rules, because it is a list. The wire member stays `rule`.
- The fourth outcome is Fault, not the generated client's ApiException. It is
  the one shared concept whose name a reader could not carry between languages,
  and an exception from the generated layer is not this layer's vocabulary.
- A client with no credential builds. It raised at construction, which is a
  process that cannot start where the other two are a process whose first call
  fails — and the first call is where the credential is actually needed.

HIP-0044 is amended where the code was right and the document was not.

ruff check, ruff format --check and mypy clean on every changed file; 109
passed. The two test_smoke failures are pre-existing (ToolsApi is absent from
the generated tree) and reproduce on a stashed working copy.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 16:26:15 -07:00
zeekayandHanzo Dev c2c8b8fd11 fix(six): ask the policy question about an org-rooted object, as the other two do
The example asked about "graph:hanzoai/python-sdk". The route parses `path` and
refuses one whose first segment is not the caller's own org, so that question
could only ever come back refused. It now reads the org off the wallet account
the budget step already named — the same construction go-sdk and js-sdk use —
and asks about "<org>/graph".

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 15:31:43 -07:00
zeekayandHanzo Dev 0a8e3272a0 fix(six): send the body /v1/authz/check reads, and stop stamping instants nobody set
policy.check was built from the route's OpenAPI description, which is stale.
The handler cloud pins — hanzoai/authz v1.10.37, serve/use.go — binds
{subject, verb, path} and answers {allow, subject, verb, path}; a body of
{sub, obj, act} gets 400 "subject, verb, path required". go-sdk and js-sdk both
send the served spelling. The caller-facing surface is unchanged: check(sub,
act, obj) -> Decision{allow, sub, act, obj, reason}.

graph left an unset instant on the body as "". Cloud reads an absent `seen` as
`at` and an absent `as_of` as now, but reads "" as a timestamp it refuses:
POST /v1/graph/ingest with at:"" answers 400 timestamp "" is not RFC 3339. An
instant nobody set is now left off.

kb.Edge takes PEP 8's keyword escape, from_ and to, rather than renaming the
pair to source and target — the word is `from`, which is what the other two
spell it. Document names and connector providers are escaped into their path
segment, as they already are in Go and TypeScript.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 15:28:12 -07:00
zeekayandHanzo Dev 7824191215 feat: budget, policy, audit, search, kb and graph on one credential
Six capabilities hang off the client as first-class methods rather than as
generated operations a caller assembles for itself: budget (allowance, wallet,
tier, charged ledger), policy (one authorization question), audit (the org's
trail, read-only by construction), search (one ranked set over every corpus),
kb (the corpus you write and the connectors that fill it), and graph
(assertions with provenance and time). The same six words, the same method
names and the same answer type as the Go and TypeScript clients.

A refused budget and a refused policy are answers. Answer is a union of three
frozen types with a discriminant — Ok, Denied, Held — so a caller reads
"denied, and here is why" without catching, and reading .value off a refusal
raises it rather than handing back a half-answer. One rule maps HTTP to an arm:
a 202 whose body says held is a hold, 402 and the four refusal codes on 403 are
refusals, and a status that decided nothing raises. Every arm carries the
x-request-id, which is the word audit.Event.request uses too — the join that
lets a caller find the row the server wrote for the call it just made.

Auth is IAM and nothing else. The client exchanges its own clientId and
clientSecret for a short-lived access token (client_credentials,
client_secret_basic, RFC 8707 resource), holds it until shortly before expiry,
and re-mints once on a 401. It no longer accepts a bearer, so HANZO_API_KEY,
Configuration(access_token=) construction and result() are gone rather than
deprecated: two ways to hold one credential is the defect this removes. as_
still scopes to a subject and now mints from the client's own token.

hanzoai resolves its public names on first use, and the capability layer is
written over the wire rather than over the generated client, so importing the
six costs milliseconds instead of 2,700 generated modules.

ruff and ruff format are clean, mypy is clean over the thirteen new and changed
modules, and 106 tests pass. The two failures in test_smoke are the ToolsApi
name the current document no longer carries, and they fail at HEAD too. The
mint was exercised against the live hanzo.id, which answers invalid_client for
a credential it does not know; the six were exercised against a stub asserting
the exact request and decoding the shapes cloud's own schemas declare.

examples/six runs the whole thing as a caller would.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 15:01:41 -07:00
zeekayandHanzo Dev e450125523 Drop the sync workflow that never ran
It has produced no run on the forge or on GitHub since it was added.
A workflow file that never fires still evaluates on every replayed
ref, so it is a hazard rather than a lane.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-09 00:27:03 -07:00
zeekayandHanzo Dev 792933d473 Move the workflows to .github/workflows
The forge reads .github/workflows natively and github.com reads nothing else,
so one directory serves both planes instead of two conventions that disagree
about which one is live. The reusable in hanzoai/ci already lives there, so a
caller naming that path now resolves to a file that exists.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 19:01:40 -07:00
zeekayandHanzo Dev d291f0f321 ci: a runner label names the platform, not the org
hanzo-build-linux-amd64, lux-build-linux-amd64, zoo-build-linux-amd64 and
every other org-prefixed spelling all meant the same machine. Which org a
job belongs to does not change which host can build it, so the org bought
one pool name per org per arch and each could go stale on its own -- the
evo host alone answered to fourteen names for one label.

One vocabulary now: linux-amd64, linux-arm64, macos-arm64, win-amd64. The
generic labels every plain workflow uses (ubuntu-latest, self-hosted) are
untouched, so naive CI keeps working.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 12:08:07 -07:00
zeekayandHanzo Dev 4ba314672d fix: call the pipeline at the address it actually lives
hanzoai/ci keeps the reusable at .github/workflows/build.yml — the one path
both planes resolve, since github.com reads a reusable only from there and the
forge reads it too. The v1 tag moved with it, so a caller still naming
.hanzo/workflows/build.yml asks for a blob that is not in the tree:

  InsertRun: read hanzoai/ci@v1:.hanzo/workflows/build.yml: object does not exist

The caller itself stays at .hanzo/workflows/cicd.yml on purpose: github.com has
no runner for these labels, so a caller placed there could never be scheduled.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 01:14:30 -07:00
zeekay 9e93ffbeb2 Name the rest of the stack without importing it
`import hanzo` ran the CLI's module body, so it needed click, rich, httpx and
everything else in the list before it could tell you its own version — on a
bare interpreter it did not import at all. It also read `__version__` back off
this module from `cli`, a cycle that only worked because the assignment
happened to sit above the import.

Both go away by naming things instead of importing them. `__getattr__`
(PEP 562) resolves a member on first touch and caches it, so `hanzo.cloud`
costs nothing until somebody wants the cloud client, and the second touch is a
dict lookup. A member that is not installed says which distribution to install
rather than raising ModuleNotFoundError from somewhere inside us.

This is the shape the npm package and the Rust crate already had: one front
door, everything behind it, nothing loaded that was not asked for. One table
maps a name to its distribution, so adding a member is one line.
2026-09-05 18:15:02 -07:00
zeekay 7f4e176d57 Regenerate against the document the deployment answers for
The projection these were generated from was a month old and predated the
compute migration, so every one of them described /v1/visor — which the API
serves at zero paths now. That is why a hand-written console client and a
generated one had drifted the same way at the same time.

No /v1/visor path survives here. The word still appears as a source-plane
value and inside gvisor and supervisor, which are not this rename.
2026-09-05 18:07:44 -07:00
zeekayandHanzo Dev eb953b9fd5 test_smoke: billing takes the seat crm no longer holds
The document at the pinned ref names no `crm` tag and serves no /v1/crm,
so `hanzoai.cloud.api.crm_api` is a module the generator had nothing to
write — the import has raised ModuleNotFoundError since the emission that
dropped it.

This is the document's call, not a generation defect. The client emits one
module per tag and its 120 modules are exactly the 120 tags api.hanzo.ai
declares, with no difference in either direction; cli's spec/cloud.json,
projected from this same ref and digest, likewise carries neither the tag
nor the routes. So the expectation moves to the spec rather than the
client moving to the expectation.

Unlike tracker, analytics and chat before it, crm did not fold into
another product: contacts, companies, opportunities and applications have
no successor address anywhere in the document. billing replaces it because
it has been in every emission since the first generated client, which is
the property the test is really asserting — that whole products, not just
the AI routes, reach the SDK.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 00:09:01 -07:00
zeekayandHanzo Dev e740bb318b test_tenant: the keys operation lives on IamApi now
The regenerated client folded KeysApi into IamApi, so the tenant test
serializes `_get_iam_keys_serialize` to read the Authorization header it
asserts on. Same path under test — mint, cache, auth_settings — one class
name later.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-03 23:49:01 -07:00
zooqueenandzeekay 9492c358cc a uv source says where, not that anything depends on it
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)
2026-09-03 23:39:20 -07:00
zooqueenandzeekay a9330efb5c one credential, one subject: the scope rides the key, not the argument
An operator holds one key and serves N customers. Until now every call it made
on a customer's behalf was indistinguishable from every other, and nothing in
the SDK could tell them apart.

`Client.as_(subject)` binds a client to one of them. IAM mints a short-lived
token for that subject — POST hanzo.id/v1/iam/tokens/issue?id=…, on IAM's own
host, the subject in the query, the grant read off the key — and the scoped
client sends it on every call, holds it until it nears expiry, and re-mints once
on a 401. No operation takes a user id, so there is none to pass wrongly.

The other half is the answer a policy holds for a human. It arrives as 202, and
202 is a 2xx: a caller who only checks for a raise reads a queued call as one
that completed and returned nothing, because no operation declares a schema for
it. `Client` raises `Held` instead, carrying the approval that gates it, and
`result()` hands the same outcome back as a value whose two arms share no member
— an `Approval` has no `value`, a `Done` has no `id`. Discrimination is on the
body, not the status: the dozen long-running operations whose 202 means
"accepted" carry their own schema and pass straight through.

`Client` is the generated `ApiClient` plus those two behaviours, so all 196
generated API classes take it unchanged and there is one client, not two.

25 tests against a stub with `RESTClientObject`'s signature — the only thing the
mint and the client ever call — pin the mint URL and query, the camelCase
response, the cache and its skew, the re-mint on 401, and that a hold raises.

(cherry picked from commit cda66ab6a5e9f51d50e161bbb3dfe96648688fa2)
2026-09-03 23:39:08 -07:00
zeekay f91d612e2c Regenerate against the current cloud document 2026-09-03 16:15:52 -07:00
zeekay fae213a6c0 Follow the cloud surface through the git rename 2026-09-03 16:15:51 -07:00
zeekay 85ad519b16 every Hanzo dependency is the version npm serves
Ranges drift once nothing moves them: a caret that has not been rewritten
since it was written pins whatever was current that day, and an exact pin
cannot even take a patch. Both are updated here.

One line per package, so a surface reads the same components, the same
tokens and the same face as every other one.
2026-09-02 02:01:33 -07:00
zeekay f43d8ae283 every Hanzo dependency is the version npm serves
Ranges drift once nothing moves them: a caret that has not been rewritten
since it was written pins whatever was current that day, and an exact pin
cannot even take a patch. Both are updated here.

One line per package, so a surface reads the same components, the same
tokens and the same face as every other one.
2026-09-01 16:13:48 -07:00
zeekayandHanzo Dev 7c2cd20df4 Merge branch 'tasks/native-http-sdk' into main
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-01 10:16:41 -07:00
zeekayandHanzo Dev 1b0b40fe34 Merge branch 'fix/zap-read-what-luxd-emits'
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-01 10:12:22 -07:00
zeekay 25c5297839 Read the model catalogue as the typed object it now is
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.
2026-09-01 10:11:09 -07:00
zeekayandHanzo Dev 39017ee7a1 hanzo-tasks: the client is the /v1/tasks contract, not a Temporal wrapper
The package dialed Temporal over gRPC, a transport hanzoai/tasks removed in
v3, so nothing it did could reach the engine. It is now the HTTP contract the
engine serves under /v1/tasks/namespaces/{ns}: start, signal-with-start, list,
describe, signal, query, cancel, terminate, reset, history, and schedules — one
method per route, IAM bearer, tested against the request shapes. A workflow's
body still runs in a Go or TypeScript worker.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-01 07:58:30 -07:00