@hanzo/ai 0.1.0
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/LICENSE +201 -0
- package/README.md +151 -0
- package/dist/index.cjs +464 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +486 -0
- package/dist/index.d.ts +486 -0
- package/dist/index.js +446 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
// src/account.ts
|
|
2
|
+
var AccountResource = class {
|
|
3
|
+
constructor(http) {
|
|
4
|
+
this.http = http;
|
|
5
|
+
}
|
|
6
|
+
http;
|
|
7
|
+
/** Returns the account for the current token's identity. */
|
|
8
|
+
get(options) {
|
|
9
|
+
return this.http.enveloped({
|
|
10
|
+
method: "GET",
|
|
11
|
+
path: "/v1/get-account",
|
|
12
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/errors.ts
|
|
18
|
+
var HanzoAIError = class extends Error {
|
|
19
|
+
constructor(message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "HanzoAIError";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var APIError = class extends HanzoAIError {
|
|
25
|
+
status;
|
|
26
|
+
body;
|
|
27
|
+
constructor(message, status, body) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = "APIError";
|
|
30
|
+
this.status = status;
|
|
31
|
+
this.body = body;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var AuthError = class extends HanzoAIError {
|
|
35
|
+
constructor(message = "No auth token available. Pass `token` or `getToken` to createAiClient.") {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "AuthError";
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/stream.ts
|
|
42
|
+
async function* parseSSE(body) {
|
|
43
|
+
const reader = body.getReader();
|
|
44
|
+
const decoder = new TextDecoder();
|
|
45
|
+
let buffer = "";
|
|
46
|
+
try {
|
|
47
|
+
while (true) {
|
|
48
|
+
const { value, done } = await reader.read();
|
|
49
|
+
if (done) break;
|
|
50
|
+
buffer += decoder.decode(value, { stream: true });
|
|
51
|
+
let sep;
|
|
52
|
+
while ((sep = indexOfBoundary(buffer)) !== -1) {
|
|
53
|
+
const rawEvent = buffer.slice(0, sep);
|
|
54
|
+
buffer = buffer.slice(boundaryEnd(buffer, sep));
|
|
55
|
+
const ev = decodeEvent(rawEvent);
|
|
56
|
+
if (ev) yield ev;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const tail = buffer.trim();
|
|
60
|
+
if (tail) {
|
|
61
|
+
const ev = decodeEvent(tail);
|
|
62
|
+
if (ev) yield ev;
|
|
63
|
+
}
|
|
64
|
+
} finally {
|
|
65
|
+
reader.releaseLock();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function indexOfBoundary(s) {
|
|
69
|
+
const lf = s.indexOf("\n\n");
|
|
70
|
+
const crlf = s.indexOf("\r\n\r\n");
|
|
71
|
+
if (lf === -1) return crlf;
|
|
72
|
+
if (crlf === -1) return lf;
|
|
73
|
+
return Math.min(lf, crlf);
|
|
74
|
+
}
|
|
75
|
+
function boundaryEnd(s, idx) {
|
|
76
|
+
return s.startsWith("\r\n\r\n", idx) ? idx + 4 : idx + 2;
|
|
77
|
+
}
|
|
78
|
+
function decodeEvent(raw) {
|
|
79
|
+
let event;
|
|
80
|
+
const dataLines = [];
|
|
81
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
82
|
+
if (line === "" || line.startsWith(":")) continue;
|
|
83
|
+
if (line.startsWith("event:")) {
|
|
84
|
+
event = line.slice(6).trim();
|
|
85
|
+
} else if (line.startsWith("data:")) {
|
|
86
|
+
dataLines.push(line.slice(5).replace(/^ /, ""));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (dataLines.length === 0 && event === void 0) return null;
|
|
90
|
+
const result = { data: dataLines.join("\n") };
|
|
91
|
+
if (event !== void 0) result.event = event;
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
function requireBody(res) {
|
|
95
|
+
if (!res.body) {
|
|
96
|
+
throw new APIError("Streaming response had no body", res.status);
|
|
97
|
+
}
|
|
98
|
+
return res.body;
|
|
99
|
+
}
|
|
100
|
+
async function* streamChatCompletion(res) {
|
|
101
|
+
for await (const ev of parseSSE(requireBody(res))) {
|
|
102
|
+
const data = ev.data;
|
|
103
|
+
if (data === "[DONE]") return;
|
|
104
|
+
if (!data) continue;
|
|
105
|
+
yield JSON.parse(data);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async function* streamMessage(res) {
|
|
109
|
+
for await (const ev of parseSSE(requireBody(res))) {
|
|
110
|
+
if (ev.data === "[DONE]" || !ev.data) continue;
|
|
111
|
+
const parsed = JSON.parse(ev.data);
|
|
112
|
+
if (ev.event && !parsed.type) parsed.type = ev.event;
|
|
113
|
+
if (parsed.type === "message_stop") {
|
|
114
|
+
yield parsed;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
yield parsed;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/chat.ts
|
|
122
|
+
var PATH = "/v1/chat/completions";
|
|
123
|
+
var Completions = class {
|
|
124
|
+
constructor(http) {
|
|
125
|
+
this.http = http;
|
|
126
|
+
}
|
|
127
|
+
http;
|
|
128
|
+
async create(params, options) {
|
|
129
|
+
if (params.stream) {
|
|
130
|
+
const res = await this.http.raw({
|
|
131
|
+
method: "POST",
|
|
132
|
+
path: PATH,
|
|
133
|
+
body: params,
|
|
134
|
+
stream: true,
|
|
135
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
136
|
+
});
|
|
137
|
+
return streamChatCompletion(res);
|
|
138
|
+
}
|
|
139
|
+
return this.http.json({
|
|
140
|
+
method: "POST",
|
|
141
|
+
path: PATH,
|
|
142
|
+
body: params,
|
|
143
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
var Chat = class {
|
|
148
|
+
completions;
|
|
149
|
+
constructor(http) {
|
|
150
|
+
this.completions = new Completions(http);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// src/chats.ts
|
|
155
|
+
var ChatMessages = class {
|
|
156
|
+
constructor(http) {
|
|
157
|
+
this.http = http;
|
|
158
|
+
}
|
|
159
|
+
http;
|
|
160
|
+
/** Lists messages, optionally scoped to a single chat thread by name. */
|
|
161
|
+
list(params, options) {
|
|
162
|
+
const query = {};
|
|
163
|
+
if (params?.chat) query.chat = params.chat;
|
|
164
|
+
if (params?.user) query.user = params.user;
|
|
165
|
+
return this.http.enveloped({
|
|
166
|
+
method: "GET",
|
|
167
|
+
path: "/v1/get-messages",
|
|
168
|
+
query,
|
|
169
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/** Fetches a single message by id ("owner/name"). */
|
|
173
|
+
get(id, options) {
|
|
174
|
+
return this.http.enveloped({
|
|
175
|
+
method: "GET",
|
|
176
|
+
path: "/v1/get-message",
|
|
177
|
+
query: { id },
|
|
178
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
/** Appends a message to a thread. */
|
|
182
|
+
append(message, options) {
|
|
183
|
+
return this.http.enveloped({
|
|
184
|
+
method: "POST",
|
|
185
|
+
path: "/v1/add-message",
|
|
186
|
+
body: message,
|
|
187
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/** Updates a message in place; `id` is "owner/name". */
|
|
191
|
+
update(id, message, options) {
|
|
192
|
+
return this.http.enveloped({
|
|
193
|
+
method: "POST",
|
|
194
|
+
path: "/v1/update-message",
|
|
195
|
+
query: { id },
|
|
196
|
+
body: message,
|
|
197
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/** Deletes a message. */
|
|
201
|
+
delete(message, options) {
|
|
202
|
+
return this.http.enveloped({
|
|
203
|
+
method: "POST",
|
|
204
|
+
path: "/v1/delete-message",
|
|
205
|
+
body: message,
|
|
206
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
var Chats = class {
|
|
211
|
+
constructor(http) {
|
|
212
|
+
this.http = http;
|
|
213
|
+
this.messages = new ChatMessages(http);
|
|
214
|
+
}
|
|
215
|
+
http;
|
|
216
|
+
messages;
|
|
217
|
+
/** Lists chat threads for a user, optionally filtered by store. */
|
|
218
|
+
list(params, options) {
|
|
219
|
+
const query = {};
|
|
220
|
+
if (params?.user) query.user = params.user;
|
|
221
|
+
if (params?.store) query.store = params.store;
|
|
222
|
+
return this.http.enveloped({
|
|
223
|
+
method: "GET",
|
|
224
|
+
path: "/v1/get-chats",
|
|
225
|
+
query,
|
|
226
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
/** Fetches a single chat thread by id ("owner/name"). */
|
|
230
|
+
get(id, options) {
|
|
231
|
+
return this.http.enveloped({
|
|
232
|
+
method: "GET",
|
|
233
|
+
path: "/v1/get-chat",
|
|
234
|
+
query: { id },
|
|
235
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/** Creates a chat thread. */
|
|
239
|
+
create(chat, options) {
|
|
240
|
+
return this.http.enveloped({
|
|
241
|
+
method: "POST",
|
|
242
|
+
path: "/v1/add-chat",
|
|
243
|
+
body: chat,
|
|
244
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/** Updates a chat thread; `id` is "owner/name". */
|
|
248
|
+
update(id, chat, options) {
|
|
249
|
+
return this.http.enveloped({
|
|
250
|
+
method: "POST",
|
|
251
|
+
path: "/v1/update-chat",
|
|
252
|
+
query: { id },
|
|
253
|
+
body: chat,
|
|
254
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/** Deletes a chat thread (and its messages, server-side). */
|
|
258
|
+
delete(chat, options) {
|
|
259
|
+
return this.http.enveloped({
|
|
260
|
+
method: "POST",
|
|
261
|
+
path: "/v1/delete-chat",
|
|
262
|
+
body: chat,
|
|
263
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// src/http.ts
|
|
269
|
+
var DEFAULT_BASE_URL = "https://api.hanzo.ai";
|
|
270
|
+
function joinUrl(baseUrl, path) {
|
|
271
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
272
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
273
|
+
return base + p;
|
|
274
|
+
}
|
|
275
|
+
function toQuery(params) {
|
|
276
|
+
if (!params) return "";
|
|
277
|
+
const usp = new URLSearchParams();
|
|
278
|
+
for (const [k, v] of Object.entries(params)) {
|
|
279
|
+
if (v !== void 0) usp.set(k, String(v));
|
|
280
|
+
}
|
|
281
|
+
const s = usp.toString();
|
|
282
|
+
return s ? `?${s}` : "";
|
|
283
|
+
}
|
|
284
|
+
var HttpClient = class {
|
|
285
|
+
baseUrl;
|
|
286
|
+
token;
|
|
287
|
+
getToken;
|
|
288
|
+
fetchImpl;
|
|
289
|
+
extraHeaders;
|
|
290
|
+
constructor(config) {
|
|
291
|
+
this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
292
|
+
this.token = config.token;
|
|
293
|
+
this.getToken = config.getToken;
|
|
294
|
+
this.extraHeaders = config.headers ?? {};
|
|
295
|
+
const f = config.fetch ?? globalThis.fetch;
|
|
296
|
+
if (typeof f !== "function") {
|
|
297
|
+
throw new APIError("No fetch implementation available; pass `fetch` in the client config.", 0);
|
|
298
|
+
}
|
|
299
|
+
this.fetchImpl = f.bind(globalThis);
|
|
300
|
+
}
|
|
301
|
+
async resolveToken() {
|
|
302
|
+
if (this.getToken) return await this.getToken();
|
|
303
|
+
if (this.token) return this.token;
|
|
304
|
+
throw new AuthError();
|
|
305
|
+
}
|
|
306
|
+
async buildHeaders(opts) {
|
|
307
|
+
const headers = new Headers(this.extraHeaders);
|
|
308
|
+
for (const [k, v] of Object.entries(opts.headers ?? {})) headers.set(k, v);
|
|
309
|
+
if (opts.body !== void 0 && !headers.has("Content-Type")) {
|
|
310
|
+
headers.set("Content-Type", "application/json");
|
|
311
|
+
}
|
|
312
|
+
if (!opts.anonymous && !headers.has("Authorization")) {
|
|
313
|
+
headers.set("Authorization", `Bearer ${await this.resolveToken()}`);
|
|
314
|
+
}
|
|
315
|
+
return headers;
|
|
316
|
+
}
|
|
317
|
+
/** Issues a request and returns the raw Response (used for streaming). */
|
|
318
|
+
async raw(opts) {
|
|
319
|
+
const url = joinUrl(this.baseUrl, opts.path) + toQuery(opts.query);
|
|
320
|
+
const headers = await this.buildHeaders(opts);
|
|
321
|
+
const init = { method: opts.method ?? "GET", headers };
|
|
322
|
+
if (opts.body !== void 0) init.body = JSON.stringify(opts.body);
|
|
323
|
+
if (opts.signal) init.signal = opts.signal;
|
|
324
|
+
const res = await this.fetchImpl(url, init);
|
|
325
|
+
if (!res.ok) await throwForResponse(res);
|
|
326
|
+
return res;
|
|
327
|
+
}
|
|
328
|
+
/** Issues a request and parses a JSON body (no envelope unwrapping). */
|
|
329
|
+
async json(opts) {
|
|
330
|
+
const res = await this.raw(opts);
|
|
331
|
+
return await res.json();
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Issues a request to a Casdoor/Casibase CRUD endpoint and unwraps the
|
|
335
|
+
* { status, msg, data } envelope, throwing on status "error".
|
|
336
|
+
*/
|
|
337
|
+
async enveloped(opts) {
|
|
338
|
+
const env = await this.json(opts);
|
|
339
|
+
if (env.status !== "ok") {
|
|
340
|
+
throw new APIError(env.msg || "Request failed", 200, env);
|
|
341
|
+
}
|
|
342
|
+
return env.data;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
async function throwForResponse(res) {
|
|
346
|
+
const text = await res.text().catch(() => "");
|
|
347
|
+
let body = text;
|
|
348
|
+
let message = `HTTP ${res.status}`;
|
|
349
|
+
if (text) {
|
|
350
|
+
try {
|
|
351
|
+
body = JSON.parse(text);
|
|
352
|
+
message = extractMessage(body) ?? message;
|
|
353
|
+
} catch {
|
|
354
|
+
message = text;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
throw new APIError(message, res.status, body);
|
|
358
|
+
}
|
|
359
|
+
function extractMessage(body) {
|
|
360
|
+
if (body && typeof body === "object") {
|
|
361
|
+
const b = body;
|
|
362
|
+
if (typeof b.msg === "string" && b.msg) return b.msg;
|
|
363
|
+
const err = b.error;
|
|
364
|
+
if (typeof err === "string") return err;
|
|
365
|
+
if (err && typeof err === "object") {
|
|
366
|
+
const m = err.message;
|
|
367
|
+
if (typeof m === "string") return m;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return void 0;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/messages.ts
|
|
374
|
+
var PATH2 = "/v1/messages";
|
|
375
|
+
var Messages = class {
|
|
376
|
+
constructor(http) {
|
|
377
|
+
this.http = http;
|
|
378
|
+
}
|
|
379
|
+
http;
|
|
380
|
+
async create(params, options) {
|
|
381
|
+
if (params.stream) {
|
|
382
|
+
const res = await this.http.raw({
|
|
383
|
+
method: "POST",
|
|
384
|
+
path: PATH2,
|
|
385
|
+
body: params,
|
|
386
|
+
stream: true,
|
|
387
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
388
|
+
});
|
|
389
|
+
return streamMessage(res);
|
|
390
|
+
}
|
|
391
|
+
return this.http.json({
|
|
392
|
+
method: "POST",
|
|
393
|
+
path: PATH2,
|
|
394
|
+
body: params,
|
|
395
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
// src/models.ts
|
|
401
|
+
var Models = class {
|
|
402
|
+
constructor(http) {
|
|
403
|
+
this.http = http;
|
|
404
|
+
}
|
|
405
|
+
http;
|
|
406
|
+
/** Lists available models. */
|
|
407
|
+
async list(options) {
|
|
408
|
+
const res = await this.http.json({
|
|
409
|
+
method: "GET",
|
|
410
|
+
path: "/v1/models",
|
|
411
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
412
|
+
});
|
|
413
|
+
return res.data;
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// src/client.ts
|
|
418
|
+
var AiClient = class {
|
|
419
|
+
/** OpenAI-compatible completions: `chat.completions.create(...)`. */
|
|
420
|
+
chat;
|
|
421
|
+
/** Anthropic Messages API: `messages.create(...)`. */
|
|
422
|
+
messages;
|
|
423
|
+
/** Model catalog: `models.list()`. */
|
|
424
|
+
models;
|
|
425
|
+
/** Portable chat threads + their messages (cross-surface store). */
|
|
426
|
+
chats;
|
|
427
|
+
/** Current signed-in account. */
|
|
428
|
+
account;
|
|
429
|
+
/** Shared transport, exposed for advanced/custom calls. */
|
|
430
|
+
http;
|
|
431
|
+
constructor(config = {}) {
|
|
432
|
+
this.http = new HttpClient(config);
|
|
433
|
+
this.chat = new Chat(this.http);
|
|
434
|
+
this.messages = new Messages(this.http);
|
|
435
|
+
this.models = new Models(this.http);
|
|
436
|
+
this.chats = new Chats(this.http);
|
|
437
|
+
this.account = new AccountResource(this.http);
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
function createAiClient(config = {}) {
|
|
441
|
+
return new AiClient(config);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export { APIError, AccountResource, AiClient, AuthError, Chat, ChatMessages, Chats, Completions, HanzoAIError, HttpClient, Messages, Models, createAiClient, joinUrl, parseSSE, streamChatCompletion, streamMessage };
|
|
445
|
+
//# sourceMappingURL=index.js.map
|
|
446
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/account.ts","../src/errors.ts","../src/stream.ts","../src/chat.ts","../src/chats.ts","../src/http.ts","../src/messages.ts","../src/models.ts","../src/client.ts"],"names":["PATH"],"mappings":"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","file":"index.js","sourcesContent":["import type { HttpClient } from \"./http.js\";\nimport type { Account } from \"./types.js\";\n\n/** Current account (/v1/get-account) — resolves the signed-in IAM user. */\nexport class AccountResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Returns the account for the current token's identity. */\n get(options?: { signal?: AbortSignal }): Promise<Account> {\n return this.http.enveloped<Account>({\n method: \"GET\",\n path: \"/v1/get-account\",\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n}\n","/** Base error for every failure surfaced by the SDK. */\nexport class HanzoAIError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"HanzoAIError\";\n }\n}\n\n/** Non-2xx HTTP response, or a CRUD envelope with status \"error\". */\nexport class APIError extends HanzoAIError {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body?: unknown) {\n super(message);\n this.name = \"APIError\";\n this.status = status;\n this.body = body;\n }\n}\n\n/** No token was available when a request required authentication. */\nexport class AuthError extends HanzoAIError {\n constructor(message = \"No auth token available. Pass `token` or `getToken` to createAiClient.\") {\n super(message);\n this.name = \"AuthError\";\n }\n}\n","import { APIError } from \"./errors.js\";\nimport type {\n AnthropicStreamEvent,\n ChatCompletionChunk,\n} from \"./types.js\";\n\n/** A single decoded Server-Sent Event. */\nexport interface SSEvent {\n event?: string;\n data: string;\n}\n\n/**\n * Parses a byte stream into SSE events. Handles chunk boundaries that split a\n * single event across reads, CRLF or LF line endings, and multi-line `data:`\n * fields per the SSE spec. Comment lines (starting with \":\") are ignored.\n */\nexport async function* parseSSE(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<SSEvent, void, unknown> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n let sep: number;\n // Events are separated by a blank line. Accept both \\n\\n and \\r\\n\\r\\n.\n while ((sep = indexOfBoundary(buffer)) !== -1) {\n const rawEvent = buffer.slice(0, sep);\n buffer = buffer.slice(boundaryEnd(buffer, sep));\n const ev = decodeEvent(rawEvent);\n if (ev) yield ev;\n }\n }\n // Flush any trailing event without a terminating blank line.\n const tail = buffer.trim();\n if (tail) {\n const ev = decodeEvent(tail);\n if (ev) yield ev;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction indexOfBoundary(s: string): number {\n const lf = s.indexOf(\"\\n\\n\");\n const crlf = s.indexOf(\"\\r\\n\\r\\n\");\n if (lf === -1) return crlf;\n if (crlf === -1) return lf;\n return Math.min(lf, crlf);\n}\n\nfunction boundaryEnd(s: string, idx: number): number {\n return s.startsWith(\"\\r\\n\\r\\n\", idx) ? idx + 4 : idx + 2;\n}\n\nfunction decodeEvent(raw: string): SSEvent | null {\n let event: string | undefined;\n const dataLines: string[] = [];\n for (const line of raw.split(/\\r?\\n/)) {\n if (line === \"\" || line.startsWith(\":\")) continue;\n if (line.startsWith(\"event:\")) {\n event = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n dataLines.push(line.slice(5).replace(/^ /, \"\"));\n }\n }\n if (dataLines.length === 0 && event === undefined) return null;\n const result: SSEvent = { data: dataLines.join(\"\\n\") };\n if (event !== undefined) result.event = event;\n return result;\n}\n\nfunction requireBody(res: Response): ReadableStream<Uint8Array> {\n if (!res.body) {\n throw new APIError(\"Streaming response had no body\", res.status);\n }\n return res.body;\n}\n\n/**\n * Yields OpenAI `chat.completion.chunk` objects from a streaming\n * /v1/chat/completions response, stopping at the `[DONE]` sentinel.\n */\nexport async function* streamChatCompletion(\n res: Response,\n): AsyncGenerator<ChatCompletionChunk, void, unknown> {\n for await (const ev of parseSSE(requireBody(res))) {\n const data = ev.data;\n if (data === \"[DONE]\") return;\n if (!data) continue;\n yield JSON.parse(data) as ChatCompletionChunk;\n }\n}\n\n/**\n * Yields Anthropic stream events from a streaming /v1/messages response. The\n * event name is carried on `type` (Anthropic also includes it in the JSON, but\n * the SSE `event:` line is authoritative when present).\n */\nexport async function* streamMessage(\n res: Response,\n): AsyncGenerator<AnthropicStreamEvent, void, unknown> {\n for await (const ev of parseSSE(requireBody(res))) {\n if (ev.data === \"[DONE]\" || !ev.data) continue;\n const parsed = JSON.parse(ev.data) as AnthropicStreamEvent;\n if (ev.event && !parsed.type) parsed.type = ev.event;\n if (parsed.type === \"message_stop\") {\n yield parsed;\n return;\n }\n yield parsed;\n }\n}\n","import type { HttpClient } from \"./http.js\";\nimport { streamChatCompletion } from \"./stream.js\";\nimport type {\n ChatCompletion,\n ChatCompletionChunk,\n ChatCompletionCreateParams,\n} from \"./types.js\";\n\nconst PATH = \"/v1/chat/completions\";\n\nexport class Completions {\n constructor(private readonly http: HttpClient) {}\n\n /** Non-streaming completion. */\n create(\n params: ChatCompletionCreateParams & { stream?: false },\n options?: { signal?: AbortSignal },\n ): Promise<ChatCompletion>;\n /** Streaming completion — yields OpenAI `chat.completion.chunk`s. */\n create(\n params: ChatCompletionCreateParams & { stream: true },\n options?: { signal?: AbortSignal },\n ): Promise<AsyncGenerator<ChatCompletionChunk, void, unknown>>;\n async create(\n params: ChatCompletionCreateParams,\n options?: { signal?: AbortSignal },\n ): Promise<ChatCompletion | AsyncGenerator<ChatCompletionChunk, void, unknown>> {\n if (params.stream) {\n const res = await this.http.raw({\n method: \"POST\",\n path: PATH,\n body: params,\n stream: true,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n return streamChatCompletion(res);\n }\n return this.http.json<ChatCompletion>({\n method: \"POST\",\n path: PATH,\n body: params,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n}\n\nexport class Chat {\n readonly completions: Completions;\n constructor(http: HttpClient) {\n this.completions = new Completions(http);\n }\n}\n","import type { HttpClient } from \"./http.js\";\nimport type { Chat, Message } from \"./types.js\";\n\n/**\n * Messages within chat threads. Backed by object.Message on the backend; a\n * message belongs to a Chat via its `chat` field. These are the durable,\n * cross-surface conversation records (distinct from a single completion call).\n */\nexport class ChatMessages {\n constructor(private readonly http: HttpClient) {}\n\n /** Lists messages, optionally scoped to a single chat thread by name. */\n list(\n params?: { chat?: string; user?: string },\n options?: { signal?: AbortSignal },\n ): Promise<Message[]> {\n const query: Record<string, string> = {};\n if (params?.chat) query.chat = params.chat;\n if (params?.user) query.user = params.user;\n return this.http.enveloped<Message[]>({\n method: \"GET\",\n path: \"/v1/get-messages\",\n query,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Fetches a single message by id (\"owner/name\"). */\n get(id: string, options?: { signal?: AbortSignal }): Promise<Message> {\n return this.http.enveloped<Message>({\n method: \"GET\",\n path: \"/v1/get-message\",\n query: { id },\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Appends a message to a thread. */\n append(message: Message, options?: { signal?: AbortSignal }): Promise<boolean> {\n return this.http.enveloped<boolean>({\n method: \"POST\",\n path: \"/v1/add-message\",\n body: message,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Updates a message in place; `id` is \"owner/name\". */\n update(id: string, message: Message, options?: { signal?: AbortSignal }): Promise<boolean> {\n return this.http.enveloped<boolean>({\n method: \"POST\",\n path: \"/v1/update-message\",\n query: { id },\n body: message,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Deletes a message. */\n delete(message: Message, options?: { signal?: AbortSignal }): Promise<boolean> {\n return this.http.enveloped<boolean>({\n method: \"POST\",\n path: \"/v1/delete-message\",\n body: message,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n}\n\n/**\n * Portable chat threads — the cross-surface conversation store shared by\n * hanzo.chat, hanzo.app, the desktop app, and hanzo-dev. A Chat is a thread\n * keyed by \"owner/name\"; its turns are ChatMessages.\n */\nexport class Chats {\n readonly messages: ChatMessages;\n constructor(private readonly http: HttpClient) {\n this.messages = new ChatMessages(http);\n }\n\n /** Lists chat threads for a user, optionally filtered by store. */\n list(\n params?: { user?: string; store?: string },\n options?: { signal?: AbortSignal },\n ): Promise<Chat[]> {\n const query: Record<string, string> = {};\n if (params?.user) query.user = params.user;\n if (params?.store) query.store = params.store;\n return this.http.enveloped<Chat[]>({\n method: \"GET\",\n path: \"/v1/get-chats\",\n query,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Fetches a single chat thread by id (\"owner/name\"). */\n get(id: string, options?: { signal?: AbortSignal }): Promise<Chat> {\n return this.http.enveloped<Chat>({\n method: \"GET\",\n path: \"/v1/get-chat\",\n query: { id },\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Creates a chat thread. */\n create(chat: Chat, options?: { signal?: AbortSignal }): Promise<boolean> {\n return this.http.enveloped<boolean>({\n method: \"POST\",\n path: \"/v1/add-chat\",\n body: chat,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Updates a chat thread; `id` is \"owner/name\". */\n update(id: string, chat: Chat, options?: { signal?: AbortSignal }): Promise<boolean> {\n return this.http.enveloped<boolean>({\n method: \"POST\",\n path: \"/v1/update-chat\",\n query: { id },\n body: chat,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Deletes a chat thread (and its messages, server-side). */\n delete(chat: Chat, options?: { signal?: AbortSignal }): Promise<boolean> {\n return this.http.enveloped<boolean>({\n method: \"POST\",\n path: \"/v1/delete-chat\",\n body: chat,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n}\n","import { APIError, AuthError } from \"./errors.js\";\nimport type { Envelope } from \"./types.js\";\n\nexport type TokenProvider = string | (() => string | Promise<string>);\n\nexport interface ClientConfig {\n /** Defaults to https://api.hanzo.ai (the Hanzo gateway). */\n baseUrl?: string;\n /** Static IAM access token (from @hanzo/iam). */\n token?: string;\n /** Lazy token source — preferred when tokens rotate/refresh. */\n getToken?: () => string | Promise<string>;\n /** Custom fetch (e.g. for tests or non-global-fetch runtimes). */\n fetch?: typeof fetch;\n /** Extra headers sent on every request. */\n headers?: Record<string, string>;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.hanzo.ai\";\n\n/** Joins the base URL with a `/v1/...` path. Never adds an `/api/` prefix. */\nexport function joinUrl(baseUrl: string, path: string): string {\n const base = baseUrl.replace(/\\/+$/, \"\");\n const p = path.startsWith(\"/\") ? path : `/${path}`;\n return base + p;\n}\n\nfunction toQuery(params?: Record<string, string | number | boolean | undefined>): string {\n if (!params) return \"\";\n const usp = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined) usp.set(k, String(v));\n }\n const s = usp.toString();\n return s ? `?${s}` : \"\";\n}\n\nexport interface RequestOptions {\n method?: string;\n path: string;\n query?: Record<string, string | number | boolean | undefined>;\n body?: unknown;\n /** When true, the request is sent without an Authorization header. */\n anonymous?: boolean;\n signal?: AbortSignal;\n /** Force a streaming (raw Response) result; skips body parsing. */\n stream?: boolean;\n headers?: Record<string, string>;\n}\n\n/**\n * Transport shared by every resource. Owns base-URL joining, lazy bearer-token\n * injection, JSON encoding, and error normalization. Knows nothing about any\n * specific endpoint.\n */\nexport class HttpClient {\n readonly baseUrl: string;\n private readonly token?: string;\n private readonly getToken?: () => string | Promise<string>;\n private readonly fetchImpl: typeof fetch;\n private readonly extraHeaders: Record<string, string>;\n\n constructor(config: ClientConfig) {\n this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n this.token = config.token;\n this.getToken = config.getToken;\n this.extraHeaders = config.headers ?? {};\n\n const f = config.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new APIError(\"No fetch implementation available; pass `fetch` in the client config.\", 0);\n }\n this.fetchImpl = f.bind(globalThis);\n }\n\n private async resolveToken(): Promise<string> {\n if (this.getToken) return await this.getToken();\n if (this.token) return this.token;\n throw new AuthError();\n }\n\n private async buildHeaders(opts: RequestOptions): Promise<Headers> {\n const headers = new Headers(this.extraHeaders);\n for (const [k, v] of Object.entries(opts.headers ?? {})) headers.set(k, v);\n if (opts.body !== undefined && !headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n if (!opts.anonymous && !headers.has(\"Authorization\")) {\n headers.set(\"Authorization\", `Bearer ${await this.resolveToken()}`);\n }\n return headers;\n }\n\n /** Issues a request and returns the raw Response (used for streaming). */\n async raw(opts: RequestOptions): Promise<Response> {\n const url = joinUrl(this.baseUrl, opts.path) + toQuery(opts.query);\n const headers = await this.buildHeaders(opts);\n const init: RequestInit = { method: opts.method ?? \"GET\", headers };\n if (opts.body !== undefined) init.body = JSON.stringify(opts.body);\n if (opts.signal) init.signal = opts.signal;\n\n const res = await this.fetchImpl(url, init);\n if (!res.ok) await throwForResponse(res);\n return res;\n }\n\n /** Issues a request and parses a JSON body (no envelope unwrapping). */\n async json<T>(opts: RequestOptions): Promise<T> {\n const res = await this.raw(opts);\n return (await res.json()) as T;\n }\n\n /**\n * Issues a request to a Casdoor/Casibase CRUD endpoint and unwraps the\n * { status, msg, data } envelope, throwing on status \"error\".\n */\n async enveloped<T>(opts: RequestOptions): Promise<T> {\n const env = await this.json<Envelope<T>>(opts);\n if (env.status !== \"ok\") {\n throw new APIError(env.msg || \"Request failed\", 200, env);\n }\n return env.data;\n }\n}\n\nasync function throwForResponse(res: Response): Promise<never> {\n const text = await res.text().catch(() => \"\");\n let body: unknown = text;\n let message = `HTTP ${res.status}`;\n if (text) {\n try {\n body = JSON.parse(text);\n message = extractMessage(body) ?? message;\n } catch {\n message = text;\n }\n }\n throw new APIError(message, res.status, body);\n}\n\n/** Pulls a human message out of OpenAI / Anthropic / Casibase error bodies. */\nfunction extractMessage(body: unknown): string | undefined {\n if (body && typeof body === \"object\") {\n const b = body as Record<string, unknown>;\n if (typeof b.msg === \"string\" && b.msg) return b.msg;\n const err = b.error;\n if (typeof err === \"string\") return err;\n if (err && typeof err === \"object\") {\n const m = (err as Record<string, unknown>).message;\n if (typeof m === \"string\") return m;\n }\n }\n return undefined;\n}\n","import type { HttpClient } from \"./http.js\";\nimport { streamMessage } from \"./stream.js\";\nimport type {\n AnthropicMessageResponse,\n AnthropicStreamEvent,\n MessageCreateParams,\n} from \"./types.js\";\n\nconst PATH = \"/v1/messages\";\n\n/** Anthropic Messages API (/v1/messages). */\nexport class Messages {\n constructor(private readonly http: HttpClient) {}\n\n /** Non-streaming message. */\n create(\n params: MessageCreateParams & { stream?: false },\n options?: { signal?: AbortSignal },\n ): Promise<AnthropicMessageResponse>;\n /** Streaming message — yields Anthropic stream events. */\n create(\n params: MessageCreateParams & { stream: true },\n options?: { signal?: AbortSignal },\n ): Promise<AsyncGenerator<AnthropicStreamEvent, void, unknown>>;\n async create(\n params: MessageCreateParams,\n options?: { signal?: AbortSignal },\n ): Promise<AnthropicMessageResponse | AsyncGenerator<AnthropicStreamEvent, void, unknown>> {\n if (params.stream) {\n const res = await this.http.raw({\n method: \"POST\",\n path: PATH,\n body: params,\n stream: true,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n return streamMessage(res);\n }\n return this.http.json<AnthropicMessageResponse>({\n method: \"POST\",\n path: PATH,\n body: params,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n}\n","import type { HttpClient } from \"./http.js\";\nimport type { Model, ModelList } from \"./types.js\";\n\n/** Model catalog (/v1/models, OpenAI-compatible). */\nexport class Models {\n constructor(private readonly http: HttpClient) {}\n\n /** Lists available models. */\n async list(options?: { signal?: AbortSignal }): Promise<Model[]> {\n const res = await this.http.json<ModelList>({\n method: \"GET\",\n path: \"/v1/models\",\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n return res.data;\n }\n}\n","import { AccountResource } from \"./account.js\";\nimport { Chat } from \"./chat.js\";\nimport { Chats } from \"./chats.js\";\nimport { HttpClient, type ClientConfig } from \"./http.js\";\nimport { Messages } from \"./messages.js\";\nimport { Models } from \"./models.js\";\n\n/**\n * The Hanzo AI client. Headless: no UI, no React, no DOM dependency beyond\n * the standard `fetch`/`ReadableStream` web APIs.\n */\nexport class AiClient {\n /** OpenAI-compatible completions: `chat.completions.create(...)`. */\n readonly chat: Chat;\n /** Anthropic Messages API: `messages.create(...)`. */\n readonly messages: Messages;\n /** Model catalog: `models.list()`. */\n readonly models: Models;\n /** Portable chat threads + their messages (cross-surface store). */\n readonly chats: Chats;\n /** Current signed-in account. */\n readonly account: AccountResource;\n /** Shared transport, exposed for advanced/custom calls. */\n readonly http: HttpClient;\n\n constructor(config: ClientConfig = {}) {\n this.http = new HttpClient(config);\n this.chat = new Chat(this.http);\n this.messages = new Messages(this.http);\n this.models = new Models(this.http);\n this.chats = new Chats(this.http);\n this.account = new AccountResource(this.http);\n }\n}\n\n/** Creates a typed Hanzo AI client. */\nexport function createAiClient(config: ClientConfig = {}): AiClient {\n return new AiClient(config);\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hanzo/ai",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Headless TypeScript client for the Hanzo AI backend — chat completions, Anthropic messages, models, and portable chat/message threads. No UI, no React.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"author": "Hanzo AI Inc.",
|
|
8
|
+
"homepage": "https://hanzo.ai",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/hanzo-js/ai.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"hanzo",
|
|
15
|
+
"ai",
|
|
16
|
+
"llm",
|
|
17
|
+
"openai",
|
|
18
|
+
"anthropic",
|
|
19
|
+
"sdk",
|
|
20
|
+
"client",
|
|
21
|
+
"chat",
|
|
22
|
+
"completions",
|
|
23
|
+
"streaming"
|
|
24
|
+
],
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"main": "./dist/index.cjs",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js",
|
|
33
|
+
"require": "./dist/index.cjs"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"test:watch": "vitest",
|
|
49
|
+
"prepublishOnly": "npm run typecheck && npm run test && npm run build"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"tsup": "^8.3.5",
|
|
53
|
+
"typescript": "^5.7.2",
|
|
54
|
+
"vitest": "^2.1.8"
|
|
55
|
+
},
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=18"
|
|
58
|
+
}
|
|
59
|
+
}
|