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.
Files changed (168) hide show
  1. package/README.md +64 -9
  2. package/dist/answer.js +20 -10
  3. package/dist/api/ai-api.d.ts +280 -14
  4. package/dist/api/ai-api.js +315 -29
  5. package/dist/api/auto-api.d.ts +64 -0
  6. package/dist/api/auto-api.js +77 -0
  7. package/dist/api/billing-api.d.ts +4 -4
  8. package/dist/api/billing-api.js +4 -4
  9. package/dist/api/git-api.d.ts +30 -0
  10. package/dist/api/git-api.js +59 -0
  11. package/dist/api/task-api.d.ts +55 -0
  12. package/dist/api/task-api.js +71 -0
  13. package/dist/client.d.ts +3 -2
  14. package/dist/client.js +4 -3
  15. package/dist/esm/answer.js +20 -10
  16. package/dist/esm/api/ai-api.d.ts +280 -14
  17. package/dist/esm/api/ai-api.js +315 -29
  18. package/dist/esm/api/auto-api.d.ts +64 -0
  19. package/dist/esm/api/auto-api.js +77 -0
  20. package/dist/esm/api/billing-api.d.ts +4 -4
  21. package/dist/esm/api/billing-api.js +4 -4
  22. package/dist/esm/api/git-api.d.ts +30 -0
  23. package/dist/esm/api/git-api.js +59 -0
  24. package/dist/esm/api/task-api.d.ts +55 -0
  25. package/dist/esm/api/task-api.js +71 -0
  26. package/dist/esm/client.d.ts +3 -2
  27. package/dist/esm/client.js +3 -2
  28. package/dist/esm/hanzo.d.ts +3 -0
  29. package/dist/esm/hanzo.js +6 -0
  30. package/dist/esm/models/agent-target-view.d.ts +6 -0
  31. package/dist/esm/models/ai-chat-in.d.ts +42 -0
  32. package/dist/esm/models/ai-chat.d.ts +37 -0
  33. package/dist/esm/models/ai-decide-in.d.ts +50 -0
  34. package/dist/esm/models/ai-decide-in.js +14 -0
  35. package/dist/esm/models/ai-decision-sides.d.ts +4 -5
  36. package/dist/esm/models/{ai-decision-sides-false.d.ts → ai-decision.d.ts} +15 -2
  37. package/dist/esm/models/ai-decision.js +14 -0
  38. package/dist/esm/models/ai-decisions-answer.d.ts +2 -3
  39. package/dist/esm/models/ai-decisions-choice.d.ts +4 -8
  40. package/dist/esm/models/ai-decisions-noul.d.ts +2 -3
  41. package/dist/esm/models/ai-decisions-request.d.ts +2 -3
  42. package/dist/esm/models/ai-decisions-score.d.ts +4 -5
  43. package/dist/esm/models/ai-model.d.ts +73 -0
  44. package/dist/esm/models/ai-model.js +14 -0
  45. package/dist/esm/models/{ai-decisions-choice-criteria-value.d.ts → ai-models.d.ts} +15 -2
  46. package/dist/esm/models/ai-models.js +14 -0
  47. package/dist/esm/models/ai-price.d.ts +48 -0
  48. package/dist/esm/models/ai-price.js +14 -0
  49. package/dist/esm/models/ai-receipt.d.ts +60 -0
  50. package/dist/esm/models/ai-receipt.js +14 -0
  51. package/dist/esm/models/ai-routing-reward-request.d.ts +54 -0
  52. package/dist/esm/models/ai-routing-reward-request.js +24 -0
  53. package/dist/esm/models/auto-automation-in.d.ts +6 -0
  54. package/dist/esm/models/auto-automation-patch.d.ts +6 -0
  55. package/dist/esm/models/auto-automation-run.d.ts +14 -1
  56. package/dist/esm/models/auto-automation.d.ts +6 -0
  57. package/dist/esm/models/auto-post-result.d.ts +36 -0
  58. package/dist/esm/models/auto-post-result.js +14 -0
  59. package/dist/esm/models/auto-review-in.d.ts +36 -0
  60. package/dist/esm/models/auto-review-in.js +14 -0
  61. package/dist/esm/models/git-workspace-view.d.ts +36 -0
  62. package/dist/esm/models/git-workspace-view.js +14 -0
  63. package/dist/esm/models/iam-user.d.ts +1 -1
  64. package/dist/esm/models/index.d.ts +14 -2
  65. package/dist/esm/models/index.js +14 -2
  66. package/dist/esm/models/provider-github-import-out.d.ts +6 -0
  67. package/dist/esm/models/provider-github-repo-item.d.ts +6 -0
  68. package/dist/esm/models/task-comment-list.d.ts +31 -0
  69. package/dist/esm/models/task-comment-list.js +14 -0
  70. package/dist/esm/models/task-comment.d.ts +42 -0
  71. package/dist/esm/models/task-comment.js +14 -0
  72. package/dist/esm/transport.d.ts +4 -0
  73. package/dist/esm/transport.js +188 -0
  74. package/dist/esm/usage.d.ts +98 -0
  75. package/dist/esm/usage.js +161 -0
  76. package/dist/hanzo.d.ts +3 -0
  77. package/dist/hanzo.js +16 -1
  78. package/dist/models/agent-target-view.d.ts +6 -0
  79. package/dist/models/ai-chat-in.d.ts +42 -0
  80. package/dist/models/ai-chat.d.ts +37 -0
  81. package/dist/models/ai-decide-in.d.ts +50 -0
  82. package/dist/models/ai-decide-in.js +15 -0
  83. package/dist/models/ai-decision-sides.d.ts +4 -5
  84. package/dist/models/{ai-decision-sides-false.d.ts → ai-decision.d.ts} +15 -2
  85. package/dist/models/ai-decision.js +15 -0
  86. package/dist/models/ai-decisions-answer.d.ts +2 -3
  87. package/dist/models/ai-decisions-choice.d.ts +4 -8
  88. package/dist/models/ai-decisions-noul.d.ts +2 -3
  89. package/dist/models/ai-decisions-request.d.ts +2 -3
  90. package/dist/models/ai-decisions-score.d.ts +4 -5
  91. package/dist/models/ai-model.d.ts +73 -0
  92. package/dist/models/ai-model.js +15 -0
  93. package/dist/models/{ai-decisions-choice-criteria-value.d.ts → ai-models.d.ts} +15 -2
  94. package/dist/models/ai-models.js +15 -0
  95. package/dist/models/ai-price.d.ts +48 -0
  96. package/dist/models/ai-price.js +15 -0
  97. package/dist/models/ai-receipt.d.ts +60 -0
  98. package/dist/models/ai-receipt.js +15 -0
  99. package/dist/models/ai-routing-reward-request.d.ts +54 -0
  100. package/dist/models/ai-routing-reward-request.js +27 -0
  101. package/dist/models/auto-automation-in.d.ts +6 -0
  102. package/dist/models/auto-automation-patch.d.ts +6 -0
  103. package/dist/models/auto-automation-run.d.ts +14 -1
  104. package/dist/models/auto-automation.d.ts +6 -0
  105. package/dist/models/auto-post-result.d.ts +36 -0
  106. package/dist/models/auto-post-result.js +15 -0
  107. package/dist/models/auto-review-in.d.ts +36 -0
  108. package/dist/models/auto-review-in.js +15 -0
  109. package/dist/models/git-workspace-view.d.ts +36 -0
  110. package/dist/models/git-workspace-view.js +15 -0
  111. package/dist/models/iam-user.d.ts +1 -1
  112. package/dist/models/index.d.ts +14 -2
  113. package/dist/models/index.js +14 -2
  114. package/dist/models/provider-github-import-out.d.ts +6 -0
  115. package/dist/models/provider-github-repo-item.d.ts +6 -0
  116. package/dist/models/task-comment-list.d.ts +31 -0
  117. package/dist/models/task-comment-list.js +15 -0
  118. package/dist/models/task-comment.d.ts +42 -0
  119. package/dist/models/task-comment.js +15 -0
  120. package/dist/transport.d.ts +4 -0
  121. package/dist/transport.js +195 -0
  122. package/dist/usage.d.ts +98 -0
  123. package/dist/usage.js +174 -0
  124. package/package.json +1 -1
  125. package/src/answer.ts +23 -10
  126. package/src/api/ai-api.ts +503 -29
  127. package/src/api/auto-api.ts +117 -0
  128. package/src/api/billing-api.ts +4 -4
  129. package/src/api/git-api.ts +68 -0
  130. package/src/api/task-api.ts +101 -0
  131. package/src/client.ts +3 -2
  132. package/src/hanzo.ts +18 -0
  133. package/src/models/agent-target-view.ts +6 -0
  134. package/src/models/ai-chat-in.ts +48 -0
  135. package/src/models/ai-chat.ts +45 -0
  136. package/src/models/ai-decide-in.ts +54 -0
  137. package/src/models/ai-decision-sides.ts +4 -7
  138. package/src/models/{ai-decision-sides-false.ts → ai-decision.ts} +17 -2
  139. package/src/models/ai-decisions-answer.ts +2 -5
  140. package/src/models/ai-decisions-choice.ts +4 -10
  141. package/src/models/ai-decisions-noul.ts +2 -5
  142. package/src/models/ai-decisions-question.ts +0 -3
  143. package/src/models/ai-decisions-request.ts +2 -5
  144. package/src/models/ai-decisions-score.ts +4 -7
  145. package/src/models/ai-model.ts +81 -0
  146. package/src/models/{ai-decisions-choice-criteria-value.ts → ai-models.ts} +17 -2
  147. package/src/models/ai-price.ts +54 -0
  148. package/src/models/ai-receipt.ts +66 -0
  149. package/src/models/ai-routing-reward-request.ts +63 -0
  150. package/src/models/auto-automation-in.ts +6 -0
  151. package/src/models/auto-automation-patch.ts +6 -0
  152. package/src/models/auto-automation-run.ts +16 -1
  153. package/src/models/auto-automation.ts +6 -0
  154. package/src/models/auto-post-result.ts +42 -0
  155. package/src/models/auto-review-in.ts +42 -0
  156. package/src/models/git-workspace-view.ts +42 -0
  157. package/src/models/iam-user.ts +1 -1
  158. package/src/models/index.ts +14 -2
  159. package/src/models/provider-github-import-out.ts +6 -0
  160. package/src/models/provider-github-repo-item.ts +6 -0
  161. package/src/models/task-comment-list.ts +39 -0
  162. package/src/models/task-comment.ts +48 -0
  163. package/src/transport.ts +190 -0
  164. package/src/usage.ts +203 -0
  165. /package/dist/esm/models/{ai-decision-sides-false.js → ai-chat-in.js} +0 -0
  166. /package/dist/esm/models/{ai-decisions-choice-criteria-value.js → ai-chat.js} +0 -0
  167. /package/dist/models/{ai-decision-sides-false.js → ai-chat-in.js} +0 -0
  168. /package/dist/models/{ai-decisions-choice-criteria-value.js → ai-chat.js} +0 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Hanzo Cloud API
3
+ * The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator\'s admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.
4
+ *
5
+ * The version of the OpenAPI document: v1
6
+ *
7
+ *
8
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
9
+ * https://openapi-generator.tech
10
+ * Do not edit the class manually.
11
+ */
12
+ import type { TaskComment } from './task-comment';
13
+ /**
14
+ *
15
+ * @export
16
+ * @interface TaskCommentList
17
+ */
18
+ export interface TaskCommentList {
19
+ /**
20
+ * Data is the conversation. Empty is an empty array, never null.
21
+ * @type {Array<TaskComment>}
22
+ * @memberof TaskCommentList
23
+ */
24
+ 'data'?: Array<TaskComment>;
25
+ /**
26
+ * Home is the GitHub repository (owner/name) the issue lives on when its board mirrors one; its conversation is read there, and Data is then empty.
27
+ * @type {string}
28
+ * @memberof TaskCommentList
29
+ */
30
+ 'home'?: string;
31
+ }
@@ -0,0 +1,14 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Hanzo Cloud API
5
+ * The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator\'s admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.
6
+ *
7
+ * The version of the OpenAPI document: v1
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+ export {};
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Hanzo Cloud API
3
+ * The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator\'s admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.
4
+ *
5
+ * The version of the OpenAPI document: v1
6
+ *
7
+ *
8
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
9
+ * https://openapi-generator.tech
10
+ * Do not edit the class manually.
11
+ */
12
+ /**
13
+ *
14
+ * @export
15
+ * @interface TaskComment
16
+ */
17
+ export interface TaskComment {
18
+ /**
19
+ * Author is who wrote it: their name, else their forge login.
20
+ * @type {string}
21
+ * @memberof TaskComment
22
+ */
23
+ 'author'?: string;
24
+ /**
25
+ * Body is what was written, as markdown.
26
+ * @type {string}
27
+ * @memberof TaskComment
28
+ */
29
+ 'body'?: string;
30
+ /**
31
+ * CreatedAt is when it was written, RFC 3339.
32
+ * @type {string}
33
+ * @memberof TaskComment
34
+ */
35
+ 'createdAt'?: string;
36
+ /**
37
+ * ID is the forge\'s id for the comment.
38
+ * @type {number}
39
+ * @memberof TaskComment
40
+ */
41
+ 'id'?: number;
42
+ }
@@ -0,0 +1,14 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Hanzo Cloud API
5
+ * The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator\'s admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.
6
+ *
7
+ * The version of the OpenAPI document: v1
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+ export {};
@@ -0,0 +1,4 @@
1
+ import { Configuration as Generated, type ConfigurationParameters } from './configuration';
2
+ export declare class Configuration extends Generated {
3
+ constructor(param?: ConfigurationParameters);
4
+ }
@@ -0,0 +1,188 @@
1
+ // transport — the Configuration this package exports.
2
+ //
3
+ // It is the generated Configuration plus one thing: a request a generated *Api
4
+ // class sends with it that comes back 402 or 429 with a usage refusal in the
5
+ // body throws that refusal's typed error (usage.ts). Every other answer passes
6
+ // through untouched — a 400 is still the AxiosError it was.
7
+ //
8
+ // The error path is axios's own: one response interceptor on the axios instance
9
+ // the generated classes use by default, installed by the first Configuration
10
+ // built. It acts only on requests marked as this package's, and the mark rides
11
+ // in `baseOptions`, which the generated client spreads into every request it
12
+ // builds — so the caller's other axios traffic, adapters and transforms are left
13
+ // as they were. An axios instance passed as an *Api's third argument has
14
+ // interceptors of its own, and a refusal through it stays an AxiosError.
15
+ //
16
+ // hanzo.ts exports this class under the generated one's name, so
17
+ // `new Configuration({ accessToken })` from 'hanzoai' is this one, and so is
18
+ // `Client.configuration`.
19
+ import axios from 'axios';
20
+ import { Configuration as Generated } from './configuration';
21
+ import { header, limited } from './usage';
22
+ /**
23
+ * The request option that marks a request as sent with this Configuration. Its
24
+ * value is this module's own interceptor, so two copies of the package sharing
25
+ * one axios each type only their own requests, with their own classes.
26
+ */
27
+ const MARK = 'hanzoUsage';
28
+ /** A stream body is read this far at most; a refusal is a few hundred bytes of JSON. */
29
+ const CAP = 1 << 16;
30
+ export class Configuration extends Generated {
31
+ constructor(param = {}) {
32
+ super(param);
33
+ this.baseOptions = { ...this.baseOptions, [MARK]: refused };
34
+ // Checked, not remembered: a test teardown's `interceptors.response.clear()`
35
+ // removes it, and the next Configuration puts it back.
36
+ const installed = axios.interceptors.response.handlers?.some((h) => h?.rejected === refused);
37
+ if (!installed)
38
+ axios.interceptors.response.use(undefined, refused);
39
+ }
40
+ }
41
+ /** Rethrow a marked 402 or 429 as the usage refusal its body names; anything else as it came. */
42
+ async function refused(err) {
43
+ const e = err;
44
+ const res = e?.response;
45
+ const config = e?.config;
46
+ if (!res || config?.[MARK] !== refused || (res.status !== 402 && res.status !== 429))
47
+ throw err;
48
+ let parsed;
49
+ try {
50
+ parsed = await body(res, config);
51
+ }
52
+ catch {
53
+ // A body that cannot be read names nothing: the answer is the one axios gave.
54
+ throw err;
55
+ }
56
+ throw limited(res.status, parsed, header(res.headers, 'x-request-id'), err) ?? err;
57
+ }
58
+ /**
59
+ * The body as JSON where it is JSON. axios hands it over parsed by default and
60
+ * raw when the caller asked for a buffer, a blob or a stream. A stream is read
61
+ * only when it says it is JSON — a refusal is, an event stream never is — at
62
+ * most CAP bytes, no longer than the caller's signal and timeout allow, and
63
+ * without taking it from the caller: `res.data` is left holding a stream of the
64
+ * same family that yields every byte again.
65
+ */
66
+ async function body(res, config) {
67
+ let data = res.data;
68
+ if (web(data) || node(data)) {
69
+ if (!/json/i.test(header(res.headers, 'content-type') ?? ''))
70
+ return undefined;
71
+ const read = web(data) ? peekWeb(data, config) : peekNode(data, config);
72
+ const { text, again } = await read;
73
+ res.data = again;
74
+ data = text;
75
+ }
76
+ else if (typeof Blob !== 'undefined' && data instanceof Blob) {
77
+ data = await data.text();
78
+ }
79
+ else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
80
+ data = new TextDecoder().decode(data);
81
+ }
82
+ if (typeof data !== 'string')
83
+ return data;
84
+ try {
85
+ return JSON.parse(data);
86
+ }
87
+ catch {
88
+ return data;
89
+ }
90
+ }
91
+ /** A WHATWG stream: the fetch and xhr adapters' `responseType: 'stream'`. */
92
+ const web = (v) => typeof v?.tee === 'function' && typeof v.getReader === 'function';
93
+ const node = (v) => typeof v?.pipe === 'function' &&
94
+ typeof v[Symbol.asyncIterator] === 'function' &&
95
+ typeof v.constructor?.from === 'function';
96
+ /** Read a WHATWG stream through `peek`, and hand back a WHATWG stream that replays it. */
97
+ async function peekWeb(stream, config) {
98
+ const reader = stream.getReader();
99
+ const { text, rest } = await peek(() => reader.read(), config);
100
+ const again = new ReadableStream({
101
+ async pull(controller) {
102
+ const step = await rest.next();
103
+ if (step.done)
104
+ controller.close();
105
+ else
106
+ controller.enqueue(step.value);
107
+ },
108
+ cancel: (reason) => reader.cancel(reason),
109
+ });
110
+ return { text, again };
111
+ }
112
+ /** Read a Node stream through `peek`; `Readable.from` comes off its own constructor, so no bundle gains node:stream. */
113
+ async function peekNode(stream, config) {
114
+ const it = stream[Symbol.asyncIterator]();
115
+ const { text, rest } = await peek(() => it.next(), config);
116
+ return { text, again: stream.constructor.from(rest) };
117
+ }
118
+ const STOP = Symbol('stop');
119
+ /**
120
+ * Read chunks until the end, CAP bytes, the caller's abort or its timeout,
121
+ * whichever comes first. `text` is the whole body only when the end was
122
+ * reached — anything less names no refusal. `rest` yields every chunk read and
123
+ * then whatever is left, including a read still in flight and a failure, so the
124
+ * caller's stream loses nothing.
125
+ */
126
+ async function peek(next, config) {
127
+ const seen = [];
128
+ const decoder = new TextDecoder();
129
+ let text = '';
130
+ let done = false;
131
+ let failed;
132
+ let pending;
133
+ let timer;
134
+ let quit;
135
+ const stop = new Promise((resolve) => {
136
+ quit = () => resolve(STOP);
137
+ const signal = config.signal;
138
+ if (signal && typeof signal.addEventListener === 'function') {
139
+ if (signal.aborted)
140
+ resolve(STOP);
141
+ signal.addEventListener('abort', () => resolve(STOP), { once: true });
142
+ }
143
+ if (config.timeout && config.timeout > 0)
144
+ timer = setTimeout(() => resolve(STOP), config.timeout);
145
+ });
146
+ try {
147
+ while (text.length < CAP) {
148
+ pending = next();
149
+ const step = await Promise.race([pending, stop]);
150
+ if (step === STOP)
151
+ break;
152
+ pending = undefined;
153
+ if (step.done) {
154
+ done = true;
155
+ break;
156
+ }
157
+ seen.push(step.value);
158
+ text += typeof step.value === 'string' ? step.value : decoder.decode(step.value, { stream: true });
159
+ }
160
+ }
161
+ catch (error) {
162
+ pending = undefined;
163
+ failed = { error };
164
+ }
165
+ finally {
166
+ if (timer)
167
+ clearTimeout(timer);
168
+ quit?.();
169
+ }
170
+ async function* rest() {
171
+ yield* seen;
172
+ if (failed)
173
+ throw failed.error;
174
+ if (pending) {
175
+ const step = await pending;
176
+ if (step.done)
177
+ return;
178
+ yield step.value;
179
+ }
180
+ while (!done) {
181
+ const step = await next();
182
+ if (step.done)
183
+ return;
184
+ yield step.value;
185
+ }
186
+ }
187
+ return { text: done ? text : undefined, rest: rest() };
188
+ }
@@ -0,0 +1,98 @@
1
+ import { type Obj } from './read';
2
+ /** One way out of a usage refusal, in the order to offer them. */
3
+ export interface UsageAction {
4
+ /** upgrade | switch | credits | topup. */
5
+ kind: string;
6
+ /** The words to put on the button. */
7
+ label?: string;
8
+ /** Where to go: the pay page, or `/v1/ai/limits` for "continue with credits". */
9
+ url?: string;
10
+ /** The plan an `upgrade` moves to. */
11
+ plan?: string;
12
+ /** The model a `switch` moves to. */
13
+ model?: string;
14
+ }
15
+ /** A priced request refused because nothing the caller holds may pay for it. */
16
+ export declare class UsageLimitError extends Error {
17
+ name: string;
18
+ /** 402 or 429. */
19
+ readonly status: number;
20
+ /** The machine code — one per subclass. */
21
+ readonly code: string;
22
+ /** `billing_error` or `rate_limit_error`. */
23
+ readonly type: string | undefined;
24
+ /** The class of usage refused: premium, ours or free. */
25
+ readonly usageClass: string | undefined;
26
+ /** The model the refusal is about. */
27
+ readonly model: string | undefined;
28
+ /** The model that answers instead, where there is one. */
29
+ readonly fallback: string | undefined;
30
+ /** When the refusal lifts by itself. */
31
+ readonly resetsAt: Date | undefined;
32
+ /** The upgrade page. */
33
+ readonly upgradeUrl: string | undefined;
34
+ readonly actions: UsageAction[];
35
+ /** `x-request-id` — the handle that finds this call in the audit trail. */
36
+ readonly request: string | undefined;
37
+ /** What the transport raised: the AxiosError on the generated client, nothing on the six. */
38
+ readonly cause: unknown;
39
+ constructor(status: number, error: Obj, request?: string, cause?: unknown);
40
+ }
41
+ /** 402 `plan_allowance_used` — the plan's included usage of the class is used, and nothing else may pay. */
42
+ export declare class PlanAllowanceUsedError extends UsageLimitError {
43
+ name: string;
44
+ }
45
+ /** 402 `paid_plan_required` — the model needs a paid plan or prepaid balance. */
46
+ export declare class PaidPlanRequiredError extends UsageLimitError {
47
+ name: string;
48
+ }
49
+ /** 429 `free_plan_cap` — the free plan's daily cap on the model is used; it lifts at `resetsAt`. */
50
+ export declare class FreePlanCapError extends UsageLimitError {
51
+ name: string;
52
+ }
53
+ /** 402 `model_cap` — the model has used its share of the plan; `fallback` answers instead. */
54
+ export declare class ModelCapError extends UsageLimitError {
55
+ name: string;
56
+ }
57
+ /** 429 `usage_cap_exceeded` — a session or day request window is spent. */
58
+ export declare class UsageCapExceededError extends UsageLimitError {
59
+ name: string;
60
+ }
61
+ /** 402 `insufficient_balance` — the known wallet balance cannot cover the request. */
62
+ export declare class InsufficientBalanceError extends UsageLimitError {
63
+ name: string;
64
+ }
65
+ /**
66
+ * The typed error a refusal names, or undefined: only a 402 or 429 whose
67
+ * `error.code` is one of the six is one. Anything else stays whatever error its
68
+ * transport already raises.
69
+ */
70
+ export declare function limited(status: number, body: unknown, request?: string, cause?: unknown): UsageLimitError | undefined;
71
+ /** What the X-Hanzo-* headers on one answer say. Each is undefined where the header is absent. */
72
+ export interface Usage {
73
+ /** X-Hanzo-Usage: ok | near | limited — where the class stands. */
74
+ usage: string | undefined;
75
+ /** X-Hanzo-Usage-Class: premium | ours | free. */
76
+ usageClass: string | undefined;
77
+ /** X-Hanzo-Paid-By: plan | credits | free. Prepaid and granted credit both read `credits`. */
78
+ paidBy: string | undefined;
79
+ /** X-Hanzo-Fallback: the model that answered instead (limited mode). */
80
+ fallback: string | undefined;
81
+ /** X-Hanzo-Served: the Hanzo SKU that answered. */
82
+ served: string | undefined;
83
+ /** X-Hanzo-Usage-Reason: the refusal code that caused a fallback. */
84
+ reason: string | undefined;
85
+ }
86
+ /** A fetch `Headers`, axios's `AxiosHeaders`, or any record of header name to value. */
87
+ export type HeaderSource = {
88
+ get(name: string): unknown;
89
+ } | Record<string, unknown>;
90
+ /**
91
+ * Read the usage headers off one answer: `readUsage(res.headers)` for an axios
92
+ * response or a fetch Response alike. Names match case-insensitively. A header
93
+ * that is absent, or present and empty, reads undefined — never 0 or "", which
94
+ * would claim the server said something it did not.
95
+ */
96
+ export declare function readUsage(headers: HeaderSource | null | undefined): Usage;
97
+ /** One header by lower-case name, matched case-insensitively; undefined where absent or empty. */
98
+ export declare function header(headers: HeaderSource | null | undefined, name: string): string | undefined;
@@ -0,0 +1,161 @@
1
+ // usage — how a priced request was paid for, and the refusals when it cannot be.
2
+ //
3
+ // Every AI answer says where the caller's plan stands in six headers, never a
4
+ // figure: X-Hanzo-Usage (ok | near | limited), -Usage-Class (premium | ours |
5
+ // free), -Paid-By (plan | credits | free), -Fallback (the model that answered
6
+ // instead), -Served (the Hanzo SKU that answered) and -Usage-Reason (the refusal
7
+ // code that caused a fallback). `readUsage` reads them off whatever headers the
8
+ // caller holds.
9
+ //
10
+ // A request nothing may pay for is refused in the OpenAI envelope,
11
+ //
12
+ // {"error": {"message", "type", "code", "class"?, "model"?, "fallback"?,
13
+ // "resets_at"?, "upgrade_url"?, "actions"?}}
14
+ //
15
+ // and six codes in it are six different facts with six different ways out, so
16
+ // each is a class: a caller tells them apart with `instanceof`, never by parsing
17
+ // the sentence. The names are the Python and Go SDKs' names. Both transports
18
+ // throw them from the error path they already had — an axios response
19
+ // interceptor for the generated client (transport.ts) and the six capabilities'
20
+ // Fault (answer.ts) — through `limited`, the one place a body becomes one.
21
+ import { list, obj } from './read';
22
+ /** A string the server sent, or undefined where it sent none — never "". */
23
+ const text = (v) => (typeof v === 'string' && v !== '' ? v : undefined);
24
+ /** An RFC 3339 instant, or undefined where none was sent or it does not parse. */
25
+ const instant = (v) => {
26
+ const s = text(v);
27
+ if (!s)
28
+ return undefined;
29
+ const d = new Date(s);
30
+ return Number.isNaN(d.getTime()) ? undefined : d;
31
+ };
32
+ /** A priced request refused because nothing the caller holds may pay for it. */
33
+ export class UsageLimitError extends Error {
34
+ constructor(status, error, request, cause) {
35
+ const code = text(error['code']) ?? '';
36
+ super(text(error['message']) ?? `HTTP ${status} ${code}`);
37
+ // Literal, not `new.target.name`, which a minifier renames.
38
+ this.name = 'UsageLimitError';
39
+ this.status = status;
40
+ this.code = code;
41
+ this.type = text(error['type']);
42
+ this.usageClass = text(error['class']);
43
+ this.model = text(error['model']);
44
+ this.fallback = text(error['fallback']);
45
+ this.resetsAt = instant(error['resets_at']);
46
+ this.upgradeUrl = text(error['upgrade_url']);
47
+ // An entry with no kind is not an action, so it is not offered.
48
+ this.actions = list(error['actions']).flatMap((a) => {
49
+ const o = obj(a);
50
+ const kind = text(o['kind']);
51
+ if (!kind)
52
+ return [];
53
+ const out = { kind };
54
+ for (const k of ['label', 'url', 'plan', 'model']) {
55
+ const v = text(o[k]);
56
+ if (v !== undefined)
57
+ out[k] = v;
58
+ }
59
+ return [out];
60
+ });
61
+ this.request = request;
62
+ this.cause = cause;
63
+ }
64
+ }
65
+ /** 402 `plan_allowance_used` — the plan's included usage of the class is used, and nothing else may pay. */
66
+ export class PlanAllowanceUsedError extends UsageLimitError {
67
+ constructor() {
68
+ super(...arguments);
69
+ this.name = 'PlanAllowanceUsedError';
70
+ }
71
+ }
72
+ /** 402 `paid_plan_required` — the model needs a paid plan or prepaid balance. */
73
+ export class PaidPlanRequiredError extends UsageLimitError {
74
+ constructor() {
75
+ super(...arguments);
76
+ this.name = 'PaidPlanRequiredError';
77
+ }
78
+ }
79
+ /** 429 `free_plan_cap` — the free plan's daily cap on the model is used; it lifts at `resetsAt`. */
80
+ export class FreePlanCapError extends UsageLimitError {
81
+ constructor() {
82
+ super(...arguments);
83
+ this.name = 'FreePlanCapError';
84
+ }
85
+ }
86
+ /** 402 `model_cap` — the model has used its share of the plan; `fallback` answers instead. */
87
+ export class ModelCapError extends UsageLimitError {
88
+ constructor() {
89
+ super(...arguments);
90
+ this.name = 'ModelCapError';
91
+ }
92
+ }
93
+ /** 429 `usage_cap_exceeded` — a session or day request window is spent. */
94
+ export class UsageCapExceededError extends UsageLimitError {
95
+ constructor() {
96
+ super(...arguments);
97
+ this.name = 'UsageCapExceededError';
98
+ }
99
+ }
100
+ /** 402 `insufficient_balance` — the known wallet balance cannot cover the request. */
101
+ export class InsufficientBalanceError extends UsageLimitError {
102
+ constructor() {
103
+ super(...arguments);
104
+ this.name = 'InsufficientBalanceError';
105
+ }
106
+ }
107
+ // A Map, not an object literal: a code of "constructor" must find nothing.
108
+ const classes = new Map([
109
+ ['plan_allowance_used', PlanAllowanceUsedError],
110
+ ['paid_plan_required', PaidPlanRequiredError],
111
+ ['free_plan_cap', FreePlanCapError],
112
+ ['model_cap', ModelCapError],
113
+ ['usage_cap_exceeded', UsageCapExceededError],
114
+ ['insufficient_balance', InsufficientBalanceError],
115
+ ]);
116
+ /**
117
+ * The typed error a refusal names, or undefined: only a 402 or 429 whose
118
+ * `error.code` is one of the six is one. Anything else stays whatever error its
119
+ * transport already raises.
120
+ */
121
+ export function limited(status, body, request, cause) {
122
+ if (status !== 402 && status !== 429)
123
+ return undefined;
124
+ const error = obj(obj(body)['error']);
125
+ const Class = classes.get(text(error['code']) ?? '');
126
+ return Class ? new Class(status, error, request, cause) : undefined;
127
+ }
128
+ /**
129
+ * Read the usage headers off one answer: `readUsage(res.headers)` for an axios
130
+ * response or a fetch Response alike. Names match case-insensitively. A header
131
+ * that is absent, or present and empty, reads undefined — never 0 or "", which
132
+ * would claim the server said something it did not.
133
+ */
134
+ export function readUsage(headers) {
135
+ return {
136
+ usage: header(headers, 'x-hanzo-usage'),
137
+ usageClass: header(headers, 'x-hanzo-usage-class'),
138
+ paidBy: header(headers, 'x-hanzo-paid-by'),
139
+ fallback: header(headers, 'x-hanzo-fallback'),
140
+ served: header(headers, 'x-hanzo-served'),
141
+ reason: header(headers, 'x-hanzo-usage-reason'),
142
+ };
143
+ }
144
+ /** One header by lower-case name, matched case-insensitively; undefined where absent or empty. */
145
+ export function header(headers, name) {
146
+ const h = headers ?? {};
147
+ let v;
148
+ if (typeof h.get === 'function') {
149
+ v = h.get(name);
150
+ }
151
+ else {
152
+ for (const [k, value] of Object.entries(h))
153
+ if (k.toLowerCase() === name)
154
+ v = value;
155
+ }
156
+ if (Array.isArray(v))
157
+ v = v[0];
158
+ if (typeof v === 'number' || typeof v === 'boolean')
159
+ v = String(v);
160
+ return typeof v === 'string' ? text(v.trim()) : undefined;
161
+ }
package/dist/hanzo.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export * from './index';
2
+ export { Configuration } from './transport';
2
3
  export { Client } from './client';
3
4
  export type { Options } from './client';
5
+ export { readUsage, UsageLimitError, PlanAllowanceUsedError, PaidPlanRequiredError, FreePlanCapError, ModelCapError, UsageCapExceededError, InsufficientBalanceError, } from './usage';
6
+ export type { Usage, UsageAction, HeaderSource } from './usage';
4
7
  export * as answer from './answer';
5
8
  export * as budget from './budget';
6
9
  export * as policy from './policy';
package/dist/hanzo.js CHANGED
@@ -58,10 +58,25 @@ var __importStar = (this && this.__importStar) || (function () {
58
58
  };
59
59
  })();
60
60
  Object.defineProperty(exports, "__esModule", { value: true });
61
- exports.graph = exports.kb = exports.search = exports.audit = exports.policy = exports.budget = exports.answer = exports.Client = void 0;
61
+ exports.graph = exports.kb = exports.search = exports.audit = exports.policy = exports.budget = exports.answer = exports.InsufficientBalanceError = exports.UsageCapExceededError = exports.ModelCapError = exports.FreePlanCapError = exports.PaidPlanRequiredError = exports.PlanAllowanceUsedError = exports.UsageLimitError = exports.readUsage = exports.Client = exports.Configuration = void 0;
62
62
  __exportStar(require("./index"), exports);
63
+ // The generated Configuration, plus typed usage refusals on every *Api call
64
+ // made with it. Named here, it shadows the one `./index` exports.
65
+ var transport_1 = require("./transport");
66
+ Object.defineProperty(exports, "Configuration", { enumerable: true, get: function () { return transport_1.Configuration; } });
63
67
  var client_1 = require("./client");
64
68
  Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return client_1.Client; } });
69
+ // What a priced answer's headers say, and the six refusals a caller can act on —
70
+ // the same names as the Python and Go SDKs.
71
+ var usage_1 = require("./usage");
72
+ Object.defineProperty(exports, "readUsage", { enumerable: true, get: function () { return usage_1.readUsage; } });
73
+ Object.defineProperty(exports, "UsageLimitError", { enumerable: true, get: function () { return usage_1.UsageLimitError; } });
74
+ Object.defineProperty(exports, "PlanAllowanceUsedError", { enumerable: true, get: function () { return usage_1.PlanAllowanceUsedError; } });
75
+ Object.defineProperty(exports, "PaidPlanRequiredError", { enumerable: true, get: function () { return usage_1.PaidPlanRequiredError; } });
76
+ Object.defineProperty(exports, "FreePlanCapError", { enumerable: true, get: function () { return usage_1.FreePlanCapError; } });
77
+ Object.defineProperty(exports, "ModelCapError", { enumerable: true, get: function () { return usage_1.ModelCapError; } });
78
+ Object.defineProperty(exports, "UsageCapExceededError", { enumerable: true, get: function () { return usage_1.UsageCapExceededError; } });
79
+ Object.defineProperty(exports, "InsufficientBalanceError", { enumerable: true, get: function () { return usage_1.InsufficientBalanceError; } });
65
80
  exports.answer = __importStar(require("./answer"));
66
81
  exports.budget = __importStar(require("./budget"));
67
82
  exports.policy = __importStar(require("./policy"));
@@ -71,6 +71,12 @@ export interface AgentTargetView {
71
71
  * @memberof AgentTargetView
72
72
  */
73
73
  'running'?: number;
74
+ /**
75
+ * Serving says whether a run the caller sends here now would be taken: the machine is the caller\'s (or the caller is an org admin), and it is online with a runner that polled for work within the last 90 seconds — the online and runner half is what dispatch checks (TargetDispatchable). A heartbeat alone keeps a machine online, not serving, and a colleague\'s machine never serves the caller.
76
+ * @type {boolean}
77
+ * @memberof AgentTargetView
78
+ */
79
+ 'serving'?: boolean;
74
80
  /**
75
81
  * Sessions is how many of the org\'s sessions are mapped to this machine, by target id OR by matching Host. All of them, whatever their status.
76
82
  * @type {number}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Hanzo Cloud API
3
+ * The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator\'s admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.
4
+ *
5
+ * The version of the OpenAPI document: v1
6
+ *
7
+ *
8
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
9
+ * https://openapi-generator.tech
10
+ * Do not edit the class manually.
11
+ */
12
+ /**
13
+ *
14
+ * @export
15
+ * @interface AiChatIn
16
+ */
17
+ export interface AiChatIn {
18
+ /**
19
+ * MaxTokens bounds the answer in tokens; 0 leaves it to the model.
20
+ * @type {number}
21
+ * @memberof AiChatIn
22
+ */
23
+ 'max_tokens'?: number;
24
+ /**
25
+ * Model is the model to answer, by id (zen5, enso, kai, anthropic/claude-sonnet-4.5 — aiModels lists them). Empty asks the deployment\'s default Hanzo model.
26
+ * @type {string}
27
+ * @memberof AiChatIn
28
+ */
29
+ 'model'?: string;
30
+ /**
31
+ * Prompt is what to ask.
32
+ * @type {string}
33
+ * @memberof AiChatIn
34
+ */
35
+ 'prompt'?: string;
36
+ /**
37
+ * System is the system message ahead of the prompt, when set.
38
+ * @type {string}
39
+ * @memberof AiChatIn
40
+ */
41
+ 'system'?: string;
42
+ }