mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
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)