ai21
Version:
AI21 TypeScript SDK
434 lines (433 loc) • 11.7 kB
JavaScript
const T = "https://api.ai21.com/studio/v1";
const c = class c {
};
c.API_KEY = process.env.AI21_API_KEY ?? void 0, c.BASE_URL = process.env.AI21_BASE_URL ?? T, c.TIMEOUT_SECONDS = process.env.AI21_TIMEOUT_SECONDS ? Number(process.env.AI21_TIMEOUT_SECONDS) : 6e4, c.MAX_RETRIES = process.env.AI21_MAX_RETRIES ? Number(process.env.AI21_MAX_RETRIES) : 3, c.LOG_LEVEL = process.env.AI21_LOG_LEVEL ?? "info";
let d = c;
class l extends Error {
}
class D extends l {
constructor() {
super("API key is required");
}
}
class R extends Error {
constructor(e) {
super(`Failed to decode chunk: ${e}`);
}
}
class h {
constructor(e) {
this.client = e;
}
}
const x = ["jamba-1.5-mini", "jamba-1.5-large"];
class U extends h {
create(e, t) {
return x.includes(e.model) && console.warn(
`Warning: The model "${e.model}" is deprecated and will be removed in a future release.
Please use jamba-mini or jamba-large instead.`
), this.client.post(
"/chat/completions",
{
body: e,
...t,
stream: e.stream ?? !1
}
);
}
}
class $ extends h {
constructor() {
super(...arguments), this.completions = new U(this.client);
}
}
const B = "1.1.1";
class A {
}
class L extends A {
async prepareFormDataRequest(e) {
const t = new FormData();
return t.append("file", e), { formData: t, headers: {} };
}
}
class g {
async handleResponse({ response: e, options: t }) {
if (t.stream) {
if (!e.body)
throw new l("Response body is null");
return this.handleStream(e);
}
const r = e.headers.get("content-type");
return r != null && r.includes("application/json") ? await e.json() : null;
}
}
const p = "data: ", O = "[DONE]";
class F {
decode(e) {
if (!e) return null;
if (e.startsWith(p))
return e.slice(p.length);
throw new R(`Invalid SSE line: ${e}`);
}
async *_iterLines(e) {
for (const t of e)
if (t.trim()) {
const r = this.decode(t);
r && (yield r);
}
}
async *readBuffer(e) {
if (e.trim()) {
const t = this.decode(e);
t && (yield t);
}
}
}
class I extends F {
async *iterLines(e) {
if (!e.body)
throw new Error("Response body is null");
const t = e.body.getReader(), r = new TextDecoder();
let s = "";
try {
for (; ; ) {
const { done: a, value: o } = await t.read();
if (a) break;
s += r.decode(o, { stream: !0 });
const i = s.split(/\r\n|\n/);
s = i.pop() || "", yield* this._iterLines(i);
}
yield* this.readBuffer(s);
} finally {
t.releaseLock();
}
}
}
class N extends F {
async *iterLines(e) {
if (!e.body)
throw new Error("Response body is null");
const t = e.body;
let r = "";
for await (const s of t) {
const a = typeof s == "string" ? s : s.toString("utf-8");
r += a;
const o = r.split(/\r\n|\n/);
r = o.pop() || "", yield* this._iterLines(o);
}
yield* this.readBuffer(r);
}
}
function q(n) {
try {
return JSON.parse(n);
} catch {
throw new R(n);
}
}
class v {
constructor(e, t) {
this.response = e, this.decoder = t || new I(), this.iterator = this.stream();
}
async *stream() {
for await (const e of this.decoder.iterLines(this.response)) {
if (e === O) break;
yield q(e);
}
}
async next() {
return this.iterator.next();
}
[Symbol.asyncIterator]() {
return this;
}
}
class M extends g {
call(e, t) {
const r = new AbortController();
return fetch(e, {
method: t.method,
headers: t != null && t.headers ? t.headers : void 0,
body: t != null && t.body ? t.body : void 0,
signal: r.signal
});
}
handleStream(e) {
return new v(e, new I());
}
}
class H extends g {
async call(e, t) {
const s = (await import("node-fetch")).default;
return s(e, {
method: t.method,
headers: t != null && t.headers ? t.headers : void 0,
body: t != null && t.body ? t.body : void 0
});
}
handleStream(e) {
return new v(e, new N());
}
}
const f = typeof window < "u" && typeof window.document < "u";
var y, S, E;
const _ = typeof self == "object" && typeof (self == null ? void 0 : self.importScripts) == "function" && (((y = self.constructor) == null ? void 0 : y.name) === "DedicatedWorkerGlobalScope" || ((S = self.constructor) == null ? void 0 : S.name) === "ServiceWorkerGlobalScope" || ((E = self.constructor) == null ? void 0 : E.name) === "SharedWorkerGlobalScope");
var b;
const w = typeof process < "u" && !!process.version && !!((b = process.versions) != null && b.node);
class k extends A {
async convertReadableStream(e) {
if (!w)
throw new Error("Stream conversion is not supported in browser environment");
const { Readable: t } = await import("stream"), r = e.getReader();
return new t({
async read() {
const { done: s, value: a } = await r.read();
s ? this.push(null) : this.push(a);
}
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async createStreamFromFilePath(e, t) {
if (!w)
throw new Error("File system operations are not supported in browser environment");
const r = await import("fs").then((s) => s.default || s);
if (!r.existsSync(e))
throw new Error(`File not found: ${e}`);
t.append("file", r.createReadStream(e), {
filename: e.split("/").pop()
});
}
async prepareFormDataRequest(e) {
try {
const t = await import("form-data").then((s) => s.default || s), r = new t();
if (typeof e == "string")
return await this.createStreamFromFilePath(e, r), this.createFormDataRequest(r);
if (!e || typeof e != "object")
throw new Error(`Unsupported file type for Node.js file upload flow: ${e}`);
if ("buffer" in e)
return r.append("file", e.buffer, {
filename: e.name,
contentType: e.type
}), this.createFormDataRequest(r);
if ("stream" in e && typeof e.stream == "function") {
const s = await this.convertReadableStream(e.stream());
return r.append("file", s, {
filename: e.name,
contentType: e.type
}), this.createFormDataRequest(r);
}
throw new Error(`Unsupported file type for Node.js file upload flow: ${e}`);
} catch (t) {
throw console.error("Error in prepareFormDataRequest:", t), t;
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
createFormDataRequest(e) {
return {
formData: e,
headers: {
"Content-Type": `multipart/form-data; boundary=${e.getBoundary()}`
}
};
}
}
function j() {
return f || _ ? new M() : new H();
}
function P() {
return f || _ ? new L() : new k();
}
const m = (n, e) => {
if (typeof e != "number" || !Number.isInteger(e))
throw new l(`${n} must be an integer`);
if (e < 0)
throw new l(`${n} must be a positive integer`);
return e;
}, W = (n, e) => {
for (const [t, r] of Object.entries(e))
Array.isArray(r) ? r.forEach((s) => n.append(t, s)) : n.append(t, r);
};
class C {
constructor({
baseURL: e,
maxRetries: t = d.MAX_RETRIES,
timeout: r = d.TIMEOUT_SECONDS,
fetch: s = j(),
filesHandler: a = P()
}) {
this.baseURL = e, this.maxRetries = m("maxRetries", t), this.timeout = m("timeout", r), this.fetch = s, this.filesHandler = a;
}
get(e, t) {
return this.prepareAndExecuteRequest("get", e, t);
}
post(e, t) {
return this.prepareAndExecuteRequest("post", e, t);
}
put(e, t) {
return this.prepareAndExecuteRequest("put", e, t);
}
delete(e, t) {
return this.prepareAndExecuteRequest("delete", e, t);
}
upload(e, t, r) {
return this.filesHandler.prepareFormDataRequest(t).then((s) => {
r != null && r.body && W(s.formData, r.body);
const a = {
...r == null ? void 0 : r.headers,
...s.headers
}, o = {
method: "post",
path: e,
body: s.formData,
headers: a
};
return this.performRequest(o).then((i) => this.fetch.handleResponse(i));
});
}
getUserAgent() {
const e = this.isRunningInBrowser() ? `browser/${typeof window < "u" ? window.navigator.userAgent : "unknown"}` : `node/${process.version}`;
return `AI21 Typescript SDK ${B} ${e}`;
}
defaultHeaders(e) {
return { ...{
Accept: "application/json",
"User-Agent": this.getUserAgent(),
...this.authHeaders(e)
}, ...e.headers };
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
authHeaders(e) {
return {};
}
buildFullUrl(e, t) {
let r = `${this.baseURL}${e}`;
if (t) {
const s = new URLSearchParams(t).toString();
r += `?${s}`;
}
return r;
}
prepareAndExecuteRequest(e, t, r) {
const s = {
method: e,
path: t,
...r
};
return s != null && s.body && (s.body = JSON.stringify(s.body), s.headers = { ...s.headers, "Content-Type": "application/json" }), this.performRequest(s).then((a) => this.fetch.handleResponse(a));
}
async performRequest(e) {
const t = this.buildFullUrl(e.path, e.query), r = {
...this.defaultHeaders(e),
...e.headers
}, s = await this.fetch.call(t, { ...e, headers: r });
if (!s.ok)
throw new l(`Request failed with status ${s.status}. ${await s.text()}`);
return { response: s, options: e };
}
isRunningInBrowser() {
return typeof window < "u" && typeof window.document < "u" && typeof fetch == "function";
}
}
class G extends h {
create(e, t) {
return this.client.post("/conversational-rag", {
body: e,
...t
});
}
}
const u = "/library/files";
class K extends h {
async create(e, t) {
const { file: r, ...s } = e;
return this.client.upload(u, r, {
body: s,
...t
});
}
get(e, t) {
return this.client.get(
`${u}/${e}`,
t
);
}
delete(e, t) {
return this.client.delete(
`${u}/${e}`,
t
);
}
list(e, t) {
return this.client.get(u, {
query: e,
...t
});
}
update(e, t) {
return this.client.put(`${u}/${e.fileId}`, {
body: e,
...t
});
}
}
class X extends C {
constructor({
apiKey: e = d.API_KEY,
baseURL: t = d.BASE_URL,
timeout: r = d.TIMEOUT_SECONDS,
maxRetries: s,
via: a,
...o
} = {}) {
const i = {
apiKey: e,
baseURL: t,
timeout: r,
maxRetries: s,
via: a,
...o
};
if (!i.dangerouslyAllowBrowser && f)
throw new l(
"AI21 client is not supported in the browser by default due to potential API key exposure. Use `dangerouslyAllowBrowser` option to `true` to override it."
);
if (e === void 0)
throw new D();
super({
baseURL: t,
timeout: r,
maxRetries: s
}), this.chat = new $(this), this.conversationalRag = new G(this), this.files = new K(this), this.apiKey = e, this.via = a ?? null, this.options = i;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
authHeaders(e) {
return {
Authorization: `Bearer ${this.apiKey}`
};
}
defaultHeaders(e) {
return {
...super.defaultHeaders(e),
"User-Agent": this.getUserAgent()
};
}
getUserAgent() {
let e = super.getUserAgent();
return this.via && (e += ` via ${this.via}`), e;
}
}
export {
X as AI21,
l as AI21Error,
C as APIClient,
h as APIResource,
$ as Chat,
U as Completions,
G as ConversationalRag,
K as Files,
D as MissingAPIKeyError,
v as Stream,
B as VERSION,
f as isBrowser,
w as isNode
};