hanzoai 8.5.621 → 8.5.640
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -9
- package/dist/answer.js +20 -10
- package/dist/api/ai-api.d.ts +280 -14
- package/dist/api/ai-api.js +315 -29
- package/dist/api/auto-api.d.ts +64 -0
- package/dist/api/auto-api.js +77 -0
- package/dist/api/billing-api.d.ts +4 -4
- package/dist/api/billing-api.js +4 -4
- package/dist/api/git-api.d.ts +30 -0
- package/dist/api/git-api.js +59 -0
- package/dist/api/task-api.d.ts +55 -0
- package/dist/api/task-api.js +71 -0
- package/dist/client.d.ts +3 -2
- package/dist/client.js +4 -3
- package/dist/esm/answer.js +20 -10
- package/dist/esm/api/ai-api.d.ts +280 -14
- package/dist/esm/api/ai-api.js +315 -29
- package/dist/esm/api/auto-api.d.ts +64 -0
- package/dist/esm/api/auto-api.js +77 -0
- package/dist/esm/api/billing-api.d.ts +4 -4
- package/dist/esm/api/billing-api.js +4 -4
- package/dist/esm/api/git-api.d.ts +30 -0
- package/dist/esm/api/git-api.js +59 -0
- package/dist/esm/api/task-api.d.ts +55 -0
- package/dist/esm/api/task-api.js +71 -0
- package/dist/esm/client.d.ts +3 -2
- package/dist/esm/client.js +3 -2
- package/dist/esm/hanzo.d.ts +3 -0
- package/dist/esm/hanzo.js +6 -0
- package/dist/esm/models/agent-target-view.d.ts +6 -0
- package/dist/esm/models/ai-chat-in.d.ts +42 -0
- package/dist/esm/models/ai-chat.d.ts +37 -0
- package/dist/esm/models/ai-decide-in.d.ts +50 -0
- package/dist/esm/models/ai-decide-in.js +14 -0
- package/dist/esm/models/ai-decision-sides.d.ts +4 -5
- package/dist/esm/models/{ai-decision-sides-false.d.ts → ai-decision.d.ts} +15 -2
- package/dist/esm/models/ai-decision.js +14 -0
- package/dist/esm/models/ai-decisions-answer.d.ts +2 -3
- package/dist/esm/models/ai-decisions-choice.d.ts +4 -8
- package/dist/esm/models/ai-decisions-noul.d.ts +2 -3
- package/dist/esm/models/ai-decisions-request.d.ts +2 -3
- package/dist/esm/models/ai-decisions-score.d.ts +4 -5
- package/dist/esm/models/ai-model.d.ts +73 -0
- package/dist/esm/models/ai-model.js +14 -0
- package/dist/esm/models/{ai-decisions-choice-criteria-value.d.ts → ai-models.d.ts} +15 -2
- package/dist/esm/models/ai-models.js +14 -0
- package/dist/esm/models/ai-price.d.ts +48 -0
- package/dist/esm/models/ai-price.js +14 -0
- package/dist/esm/models/ai-receipt.d.ts +60 -0
- package/dist/esm/models/ai-receipt.js +14 -0
- package/dist/esm/models/ai-routing-reward-request.d.ts +54 -0
- package/dist/esm/models/ai-routing-reward-request.js +24 -0
- package/dist/esm/models/auto-automation-in.d.ts +6 -0
- package/dist/esm/models/auto-automation-patch.d.ts +6 -0
- package/dist/esm/models/auto-automation-run.d.ts +14 -1
- package/dist/esm/models/auto-automation.d.ts +6 -0
- package/dist/esm/models/auto-post-result.d.ts +36 -0
- package/dist/esm/models/auto-post-result.js +14 -0
- package/dist/esm/models/auto-review-in.d.ts +36 -0
- package/dist/esm/models/auto-review-in.js +14 -0
- package/dist/esm/models/git-workspace-view.d.ts +36 -0
- package/dist/esm/models/git-workspace-view.js +14 -0
- package/dist/esm/models/iam-user.d.ts +1 -1
- package/dist/esm/models/index.d.ts +14 -2
- package/dist/esm/models/index.js +14 -2
- package/dist/esm/models/provider-github-import-out.d.ts +6 -0
- package/dist/esm/models/provider-github-repo-item.d.ts +6 -0
- package/dist/esm/models/task-comment-list.d.ts +31 -0
- package/dist/esm/models/task-comment-list.js +14 -0
- package/dist/esm/models/task-comment.d.ts +42 -0
- package/dist/esm/models/task-comment.js +14 -0
- package/dist/esm/transport.d.ts +4 -0
- package/dist/esm/transport.js +188 -0
- package/dist/esm/usage.d.ts +98 -0
- package/dist/esm/usage.js +161 -0
- package/dist/hanzo.d.ts +3 -0
- package/dist/hanzo.js +16 -1
- package/dist/models/agent-target-view.d.ts +6 -0
- package/dist/models/ai-chat-in.d.ts +42 -0
- package/dist/models/ai-chat.d.ts +37 -0
- package/dist/models/ai-decide-in.d.ts +50 -0
- package/dist/models/ai-decide-in.js +15 -0
- package/dist/models/ai-decision-sides.d.ts +4 -5
- package/dist/models/{ai-decision-sides-false.d.ts → ai-decision.d.ts} +15 -2
- package/dist/models/ai-decision.js +15 -0
- package/dist/models/ai-decisions-answer.d.ts +2 -3
- package/dist/models/ai-decisions-choice.d.ts +4 -8
- package/dist/models/ai-decisions-noul.d.ts +2 -3
- package/dist/models/ai-decisions-request.d.ts +2 -3
- package/dist/models/ai-decisions-score.d.ts +4 -5
- package/dist/models/ai-model.d.ts +73 -0
- package/dist/models/ai-model.js +15 -0
- package/dist/models/{ai-decisions-choice-criteria-value.d.ts → ai-models.d.ts} +15 -2
- package/dist/models/ai-models.js +15 -0
- package/dist/models/ai-price.d.ts +48 -0
- package/dist/models/ai-price.js +15 -0
- package/dist/models/ai-receipt.d.ts +60 -0
- package/dist/models/ai-receipt.js +15 -0
- package/dist/models/ai-routing-reward-request.d.ts +54 -0
- package/dist/models/ai-routing-reward-request.js +27 -0
- package/dist/models/auto-automation-in.d.ts +6 -0
- package/dist/models/auto-automation-patch.d.ts +6 -0
- package/dist/models/auto-automation-run.d.ts +14 -1
- package/dist/models/auto-automation.d.ts +6 -0
- package/dist/models/auto-post-result.d.ts +36 -0
- package/dist/models/auto-post-result.js +15 -0
- package/dist/models/auto-review-in.d.ts +36 -0
- package/dist/models/auto-review-in.js +15 -0
- package/dist/models/git-workspace-view.d.ts +36 -0
- package/dist/models/git-workspace-view.js +15 -0
- package/dist/models/iam-user.d.ts +1 -1
- package/dist/models/index.d.ts +14 -2
- package/dist/models/index.js +14 -2
- package/dist/models/provider-github-import-out.d.ts +6 -0
- package/dist/models/provider-github-repo-item.d.ts +6 -0
- package/dist/models/task-comment-list.d.ts +31 -0
- package/dist/models/task-comment-list.js +15 -0
- package/dist/models/task-comment.d.ts +42 -0
- package/dist/models/task-comment.js +15 -0
- package/dist/transport.d.ts +4 -0
- package/dist/transport.js +195 -0
- package/dist/usage.d.ts +98 -0
- package/dist/usage.js +174 -0
- package/package.json +1 -1
- package/src/answer.ts +23 -10
- package/src/api/ai-api.ts +503 -29
- package/src/api/auto-api.ts +117 -0
- package/src/api/billing-api.ts +4 -4
- package/src/api/git-api.ts +68 -0
- package/src/api/task-api.ts +101 -0
- package/src/client.ts +3 -2
- package/src/hanzo.ts +18 -0
- package/src/models/agent-target-view.ts +6 -0
- package/src/models/ai-chat-in.ts +48 -0
- package/src/models/ai-chat.ts +45 -0
- package/src/models/ai-decide-in.ts +54 -0
- package/src/models/ai-decision-sides.ts +4 -7
- package/src/models/{ai-decision-sides-false.ts → ai-decision.ts} +17 -2
- package/src/models/ai-decisions-answer.ts +2 -5
- package/src/models/ai-decisions-choice.ts +4 -10
- package/src/models/ai-decisions-noul.ts +2 -5
- package/src/models/ai-decisions-question.ts +0 -3
- package/src/models/ai-decisions-request.ts +2 -5
- package/src/models/ai-decisions-score.ts +4 -7
- package/src/models/ai-model.ts +81 -0
- package/src/models/{ai-decisions-choice-criteria-value.ts → ai-models.ts} +17 -2
- package/src/models/ai-price.ts +54 -0
- package/src/models/ai-receipt.ts +66 -0
- package/src/models/ai-routing-reward-request.ts +63 -0
- package/src/models/auto-automation-in.ts +6 -0
- package/src/models/auto-automation-patch.ts +6 -0
- package/src/models/auto-automation-run.ts +16 -1
- package/src/models/auto-automation.ts +6 -0
- package/src/models/auto-post-result.ts +42 -0
- package/src/models/auto-review-in.ts +42 -0
- package/src/models/git-workspace-view.ts +42 -0
- package/src/models/iam-user.ts +1 -1
- package/src/models/index.ts +14 -2
- package/src/models/provider-github-import-out.ts +6 -0
- package/src/models/provider-github-repo-item.ts +6 -0
- package/src/models/task-comment-list.ts +39 -0
- package/src/models/task-comment.ts +48 -0
- package/src/transport.ts +190 -0
- package/src/usage.ts +203 -0
- /package/dist/esm/models/{ai-decision-sides-false.js → ai-chat-in.js} +0 -0
- /package/dist/esm/models/{ai-decisions-choice-criteria-value.js → ai-chat.js} +0 -0
- /package/dist/models/{ai-decision-sides-false.js → ai-chat-in.js} +0 -0
- /package/dist/models/{ai-decisions-choice-criteria-value.js → ai-chat.js} +0 -0
package/README.md
CHANGED
|
@@ -67,7 +67,10 @@ type Completion = { choices?: Array<{ message?: { content?: string } }> };
|
|
|
67
67
|
|
|
68
68
|
async function main() {
|
|
69
69
|
const { data } = await new AiApi(config).postChatCompletions({
|
|
70
|
-
|
|
70
|
+
openaiChatCompletionRequest: {
|
|
71
|
+
model: 'zen5',
|
|
72
|
+
messages: [{ role: 'user', content: 'Say hello in five words.' }],
|
|
73
|
+
},
|
|
71
74
|
});
|
|
72
75
|
const reply = data as unknown as Completion;
|
|
73
76
|
console.log(reply.choices?.[0]?.message?.content);
|
|
@@ -82,8 +85,8 @@ those, construct a `Configuration` with no `accessToken` and the client sends no
|
|
|
82
85
|
`Authorization` header.
|
|
83
86
|
|
|
84
87
|
A generated call that gets a status outside 2xx throws axios's `AxiosError`,
|
|
85
|
-
with the status on `err.response.status`, after one request
|
|
86
|
-
retried. A 200 whose body is an error object resolves like any other 200, and a
|
|
88
|
+
with the status on `err.response.status`, after one request — or, for a usage
|
|
89
|
+
refusal, its own class (below). Nothing is retried. A 200 whose body is an error object resolves like any other 200, and a
|
|
87
90
|
completion's content comes back as the server sent it, `<think>` blocks
|
|
88
91
|
included.
|
|
89
92
|
|
|
@@ -94,6 +97,55 @@ environment, and mints its own token rather than being handed one.
|
|
|
94
97
|
`GET /v1/iam/oauth/userinfo` is how you check a token: it answers the token's
|
|
95
98
|
identity, or `401 {"error":"invalid_token"}`. That is the `hello` flow below.
|
|
96
99
|
|
|
100
|
+
## Plan usage
|
|
101
|
+
|
|
102
|
+
Every AI answer says how it was paid for in `X-Hanzo-*` headers. `readUsage`
|
|
103
|
+
reads them off an axios response, a fetch `Response` or a plain record; an
|
|
104
|
+
absent header reads `undefined`.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { AiApi, Configuration, ModelCapError, UsageLimitError, readUsage } from 'hanzoai';
|
|
108
|
+
|
|
109
|
+
const ai = new AiApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
|
|
110
|
+
try {
|
|
111
|
+
const res = await ai.postChatCompletions({
|
|
112
|
+
openaiChatCompletionRequest: { model: 'anthropic/claude-sonnet-4.5', messages },
|
|
113
|
+
});
|
|
114
|
+
readUsage(res.headers); // { usage: 'ok', usageClass: 'premium', paidBy: 'credits', served: '…', fallback: undefined, reason: undefined }
|
|
115
|
+
} catch (err) {
|
|
116
|
+
if (err instanceof ModelCapError) retry(err.fallback);
|
|
117
|
+
else if (err instanceof UsageLimitError) offer(err.actions);
|
|
118
|
+
else throw err;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
A 402 or 429 refusal nothing may pay for throws a subclass of
|
|
123
|
+
`UsageLimitError`, which carries `status`, `code`, `type`, `usageClass`,
|
|
124
|
+
`model`, `fallback`, `resetsAt`, `upgradeUrl`, `actions`, `request` (the
|
|
125
|
+
`x-request-id`) and, from a generated call, `cause` (the `AxiosError`):
|
|
126
|
+
|
|
127
|
+
| class | status | `code` |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| `PlanAllowanceUsedError` | 402 | `plan_allowance_used` |
|
|
130
|
+
| `PaidPlanRequiredError` | 402 | `paid_plan_required` |
|
|
131
|
+
| `FreePlanCapError` | 429 | `free_plan_cap` |
|
|
132
|
+
| `ModelCapError` | 402 | `model_cap` |
|
|
133
|
+
| `UsageCapExceededError` | 429 | `usage_cap_exceeded` |
|
|
134
|
+
| `InsufficientBalanceError` | 402 | `insufficient_balance` |
|
|
135
|
+
|
|
136
|
+
Any other refusal stays an `AxiosError`, as does a refusal through an `*Api`
|
|
137
|
+
built without the package's `Configuration` or with an axios instance of your
|
|
138
|
+
own. A `responseType: 'stream'` JSON body is read for the code, within the
|
|
139
|
+
request's `signal` and `timeout`, and left whole on `err.cause.response.data`. `Client`'s six throw
|
|
140
|
+
these where they would throw `answer.Fault`; a 402 there is still the `denied`
|
|
141
|
+
arm.
|
|
142
|
+
|
|
143
|
+
The routes are generated: `aiLimits()` and `aiSetLimits({ aiLimitsSet: {
|
|
144
|
+
creditsAfterAllowance } })` on `/v1/ai/limits`; `SyncApi`'s `getSync`,
|
|
145
|
+
`getSyncById`, `postSync` and `postSyncByIdRun` ("sync now") on `/v1/sync`;
|
|
146
|
+
`postDecisions`; and `getModels`, whose rows carry `class` (premium, ours or
|
|
147
|
+
free), `family` and `pricing.variable`.
|
|
148
|
+
|
|
97
149
|
## The six capabilities
|
|
98
150
|
|
|
99
151
|
Budget, policy, audit, search, kb and graph — the same six words in the Go,
|
|
@@ -166,7 +218,7 @@ Types are namespaced by capability: `budget.Allowance`, `search.Hit`,
|
|
|
166
218
|
|
|
167
219
|
## Examples
|
|
168
220
|
|
|
169
|
-
|
|
221
|
+
Nine flows under [`examples/`](examples), one directory each, every one a
|
|
170
222
|
complete program:
|
|
171
223
|
|
|
172
224
|
| flow | what it does | routes |
|
|
@@ -179,6 +231,7 @@ complete program:
|
|
|
179
231
|
| [`agent`](examples/agent) | create + run + read | `POST /v1/agent`, `POST /v1/agent/{ref}/run`, `GET /v1/agent/{ref}/runs` |
|
|
180
232
|
| [`tools`](examples/tools) | tool catalog | `GET /v1/tool` |
|
|
181
233
|
| [`six`](examples/six) | budget → policy → search → kb → graph → audit, in one pass | the six capabilities |
|
|
234
|
+
| [`limits`](examples/limits) | plan, catalog by class, who paid, a typed refusal, repo links | `GET /v1/ai/limits`, `GET /v1/models`, `POST /v1/chat/completions`, `POST /v1/decisions`, `GET /v1/sync` |
|
|
182
235
|
|
|
183
236
|
`models` runs with nothing exported:
|
|
184
237
|
|
|
@@ -189,8 +242,8 @@ npm ci && npm run build && npx tsx examples/models/index.ts
|
|
|
189
242
|
(`npm run build` first because the examples import `hanzoai` by name and the
|
|
190
243
|
package resolves its own name through `exports`, which points at `dist/`.)
|
|
191
244
|
|
|
192
|
-
|
|
193
|
-
`HANZO_CLIENT_ID`/`HANZO_CLIENT_SECRET`; all
|
|
245
|
+
Seven of the others read `HANZO_API_KEY` and `six` reads
|
|
246
|
+
`HANZO_CLIENT_ID`/`HANZO_CLIENT_SECRET`; all nine talk to
|
|
194
247
|
`https://api.hanzo.ai` unless `HANZO_BASE_URL` says otherwise:
|
|
195
248
|
|
|
196
249
|
```bash
|
|
@@ -202,8 +255,9 @@ A token the server refuses answers `HTTP 401:
|
|
|
202
255
|
{"error":"invalid_token","error_description":"the access token is invalid or
|
|
203
256
|
revoked"}`.
|
|
204
257
|
|
|
205
|
-
`npm run examples` type-checks all
|
|
206
|
-
runs the six against a scripted `fetch`, and `hanzo.yml`
|
|
258
|
+
`npm run examples` type-checks all nine against the client, `npm run wire`
|
|
259
|
+
runs the six and the usage refusals against a scripted `fetch`, and `hanzo.yml`
|
|
260
|
+
makes both a CI gate.
|
|
207
261
|
|
|
208
262
|
## The API surface
|
|
209
263
|
|
|
@@ -247,7 +301,8 @@ knob lives once, in that repo's `generate.py` and `sdks.yaml`.
|
|
|
247
301
|
|
|
248
302
|
`.generated` lists what the driver owns. A file it does not name is this repo's
|
|
249
303
|
own and a regeneration never touches it — which is where `hanzo.ts`,
|
|
250
|
-
`client.ts`, `answer.ts` and the six capabilities
|
|
304
|
+
`client.ts`, `answer.ts`, `usage.ts`, `transport.ts` and the six capabilities
|
|
305
|
+
live.
|
|
251
306
|
|
|
252
307
|
Requires java 17+ and [uv](https://docs.astral.sh/uv/).
|
|
253
308
|
|
package/dist/answer.js
CHANGED
|
@@ -15,6 +15,7 @@ exports.arm = arm;
|
|
|
15
15
|
exports.value = value;
|
|
16
16
|
exports.page = page;
|
|
17
17
|
const read_1 = require("./read");
|
|
18
|
+
const usage_1 = require("./usage");
|
|
18
19
|
/**
|
|
19
20
|
* An outcome with no decision in it.
|
|
20
21
|
*
|
|
@@ -58,15 +59,17 @@ const refusals = new Set(['spend_cap_exceeded', 'insufficient_balance']);
|
|
|
58
59
|
function refusal(body) {
|
|
59
60
|
const b = (0, read_1.obj)(body);
|
|
60
61
|
// RFC 9457 spells the code `code` and the sentence `detail`; the spend gate's
|
|
61
|
-
// own body spells them `error` and `message` and adds `product` and `cure[]
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
62
|
+
// own body spells them `error` and `message` and adds `product` and `cure[]`;
|
|
63
|
+
// the AI gateway's OpenAI envelope nests `code` and `message` under `error`.
|
|
64
|
+
// The spend gate's `reason` — "unpaid", "unresolved" — names the admit leg that
|
|
65
|
+
// failed rather than explaining anything to a person, so it is not read. One
|
|
66
|
+
// reader, named fallbacks — not three paths — so it keeps working unchanged
|
|
67
|
+
// when cloud settles on one envelope.
|
|
68
|
+
const e = (0, read_1.obj)(b['error']);
|
|
66
69
|
const product = (0, read_1.str)(b['product']);
|
|
67
70
|
return {
|
|
68
|
-
code: (0, read_1.str)(b['code']) || (0, read_1.str)(b['error']),
|
|
69
|
-
reason: (0, read_1.str)(b['detail']) || (0, read_1.str)(b['message']),
|
|
71
|
+
code: (0, read_1.str)(b['code']) || (0, read_1.str)(b['error']) || (0, read_1.str)(e['code']),
|
|
72
|
+
reason: (0, read_1.str)(b['detail']) || (0, read_1.str)(b['message']) || (0, read_1.str)(e['message']),
|
|
70
73
|
...(product ? { product } : {}),
|
|
71
74
|
cures: (0, read_1.list)(b['cure']).map((c) => {
|
|
72
75
|
const cure = (0, read_1.obj)(c);
|
|
@@ -107,14 +110,21 @@ function arm(r, read) {
|
|
|
107
110
|
if (r.status === 402 || (r.status === 403 && refusals.has(said.code))) {
|
|
108
111
|
return { status: 'denied', ...said, request: r.request };
|
|
109
112
|
}
|
|
110
|
-
throw
|
|
113
|
+
throw fault(r, said);
|
|
111
114
|
}
|
|
112
115
|
/** A read no gate refuses: the value, or a [Fault] because nothing was decided. */
|
|
113
116
|
function value(r, read) {
|
|
114
117
|
if (r.status >= 200 && r.status < 300)
|
|
115
118
|
return read(r.body);
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
throw fault(r, refusal(r.body));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* What a call that decided nothing throws: the usage refusal the body names
|
|
123
|
+
* (usage.ts), or a [Fault]. What [arm] reads as [Denied] never reaches here.
|
|
124
|
+
*/
|
|
125
|
+
function fault(r, said) {
|
|
126
|
+
return ((0, usage_1.limited)(r.status, r.body, r.request || undefined) ??
|
|
127
|
+
new Fault(r.status, said.code, said.reason || `HTTP ${r.status}`, r.request));
|
|
118
128
|
}
|
|
119
129
|
/** `{data, total}` — the page shape every listing on this wire answers with. */
|
|
120
130
|
function page(body, read) {
|