JavaScript SDK
Use TypeSafe's official package, @typesafe-ai/sdk, for JavaScript and TypeScript, and point it at VAKYN MAX or your own server.
Install
npm install @typesafe-ai/sdk # Node.js 20 or newerThe package ships ESM, CommonJS and TypeScript types. The examples use top-level await, so save them as .mjs files (or set "type": "module"). They were run against open-server with @typesafe-ai/sdk 0.6.0; the package's own reference is at docs.typesafe.ai.
Point it at VAKYN
| Option | Environment variable | Default |
|---|---|---|
baseURL | TYPESAFE_BASE_URL | https://api.typesafe.ai |
apiKey | TYPESAFE_API_KEY | none, required |
defaultModel | TYPESAFE_DEFAULT_MODEL | jev-latest |
logLevel | TYPESAFE_LOG_LEVEL | warn |
Set baseURL to https://api.vakyn.com for VAKYN MAX, or to your server without /v1, and apiKey to a vk_… key issued there. Explicit options win over the environment:
import { TypeSafeClient } from "@typesafe-ai/sdk"; const client = new TypeSafeClient({ baseURL: "https://api.vakyn.com", // VAKYN MAX, without /v1 apiKey: "vk_your_key_here", // from vakyn.com/console/keys timeout: 30_000, // milliseconds per attempt retry: { maxRetries: 4 }, // 429 and 5xx are retried});console.log((await client.models.list()).map((m) => m.name));Ask questions
systemOne({ state, questions }) sends one request. The helpers noul(), choice() and score() build questions, and the answer types follow from them: with TypeScript, answers.team.choice is typed as the union of your option names.
import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk"; // Reads TYPESAFE_BASE_URL (https://api.vakyn.com) and TYPESAFE_API_KEY from the environment.const client = new TypeSafeClient();const { answers } = await client.systemOne({ state: { channel: "email", customer: { plan: "team", seats: 12, months_active: 14 }, message: "Since this morning nobody on our team can sign in. We have a client demo at 3pm.", }, questions: { outage: noul("Is the customer unable to use the product?"), team: choice("Which team should handle this?", { billing: "Invoices, charges and refunds", access: "Sign-in, passwords and permissions", product: "Bugs and how-to questions", }), urgency: score("How soon does this need a reply?", ["Can wait", "Today", "Within the hour"]), },});console.log(answers.outage.noul, answers.team.choice, answers.urgency.score);noul(instructions?, criteria?),choice(instructions, criteria),score(instructions, levels); passnullfor no instructions.score()needs at least two levels.- The result has
model,answersandusage. Add.withResponse()to the call to also getrequestIdand the rawresponse. await client.models.list()returns the array of models.
Errors and retries
Non-2xx responses reject with an APIError subclass carrying status, body, headers and requestId; RateLimitError also has retryAfterMs.
import { APIConnectionError, AuthenticationError, BadRequestError, RateLimitError, score, TypeSafeClient, UnprocessableEntityError,} from "@typesafe-ai/sdk"; // Reads TYPESAFE_BASE_URL (https://api.vakyn.com) and TYPESAFE_API_KEY from the environment.const client = new TypeSafeClient();try { const levels = Array.from({ length: 11 }, (_, i) => `level ${i}`); // one level too many const { data, requestId } = await client .systemOne({ state: "Rate this.", questions: { rating: score(null, levels) } }) .withResponse(); console.log(requestId, data.answers.rating.score);} catch (e) { if (e instanceof BadRequestError) { // 400: over a limit, or an unknown model console.log(e.status, e.body.detail, e.requestId); } else if (e instanceof UnprocessableEntityError) { console.log(e.body.detail); // 422: the body does not match the schema } else if (e instanceof AuthenticationError) { console.log("check TYPESAFE_API_KEY"); // 401: missing, wrong or revoked key } else if (e instanceof RateLimitError) { console.log("server busy"); // 429 that outlasted the retries } else if (e instanceof APIConnectionError) { console.log("cannot reach the server"); // wrong base URL, server down, timeout } else { throw e; }}Retries: two by default, with backoff, on 408, 429 and 5xx and on connection errors, honoring retry-after. Override with retry: { maxRetries, … } on the client or per call. Timeouts are per attempt, in milliseconds (default 10,000); raise them for long documents on a CPU-only server. VAKYN MAX answers 402 when the balance is empty; see Errors.
Many requests
import { noul, TypeSafeClient } from "@typesafe-ai/sdk"; // Reads TYPESAFE_BASE_URL (https://api.vakyn.com) and TYPESAFE_API_KEY from the environment.const client = new TypeSafeClient();const messages = [ "Where is my parcel?", "Please cancel my subscription at the end of the month.", "Your app crashes when I open settings.",]; // The server queues what it can take and answers 429 beyond that;// the SDK retries 429 after the delay the server asks for.const results = await Promise.all( messages.map((m) => client.systemOne({ state: m, questions: { cancel: noul("Does the customer want to cancel?") } }), ),);results.forEach((r, i) => console.log(r.answers.cancel.noul.toFixed(2), messages[i]));Differences from TypeSafe's hosted API
- Use
jev-latestor the name frommodels.list(); dated hosted model names are not available. - Keys start with
vk_and come from the VAKYN console or your own server.