SDKs
TypeScript SDK
@newmen-ai/sdk · ESM and CJS · Node 20+, Bun, Deno, browsers, edge.
The TypeScript SDK is hand-written for ergonomics, with response types generated from the OpenAPI spec so it cannot drift from the wire format. It ships at @newmen-ai/sdk on npm.
Do you even need the SDK?
OPENAI_BASE_URL (or ANTHROPIC_BASE_URL) and keep their existing client. See the migration guide. Reach for @newmen-ai/sdk only when you want first-class helpers for the Pro reliability loop — operations, feedback, datasets, and evaluators — in one typed client.Install
bashpnpm add @newmen-ai/sdk
# or: npm install @newmen-ai/sdk
# or: yarn add @newmen-ai/sdk
# or: bun add @newmen-ai/sdkInitialize
typescriptimport Newmen from "@newmen-ai/sdk";
const client = new Newmen({
apiKey: process.env.NEWMEN_API_KEY,
// baseURL defaults to https://api.newmen.ai/v1
});The constructor accepts apiKey, baseURL, timeout, maxRetries, and defaultHeaders.
operation_id (Pro)
metadata.operation_id is what unlocks the Pro reliability loop — per-operation routing, eval-gated auto-refund, datasets, and training. Calls without one are recorded and billed normally and still get pay-as-you-go pricing and thumbs-down refunds; they just aren’t grouped into an operation.Passing a new operation_id in metadata auto-registers a lightweight entry. You can start tagging traffic immediately. To attach evaluators, ship gates, or an output schema — which are required for datasets and training — formally define the operation via the console or API. See Operations.
Chat completions
typescriptconst res = await client.chat.completions.create({
model: "atlas-1",
messages: [{ role: "user", content: "Summarise this ticket." }],
metadata: { operation_id: "summarize_ticket" },
});
console.log(res.choices[0].message.content);
console.log("call_id:", res.id); // save this to attach feedbackStreaming
typescriptfor await (const chunk of client.chat.completions.stream({
model: "atlas-1",
messages,
metadata: { operation_id: "summarize_ticket" },
})) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}Streaming returns an async iterator with full AbortController support. The full response is recorded server-side after the stream closes.
Schema version
When you change the output_schema on an operation — adding a field, removing one, changing a type — pass schema_version alongside operation_id so traffic is bucketed by the schema it was generated against. Datasets and evaluators are then scoped to a single version; old and new shapes never pollute the same training set.
typescript// When you change output_schema on an operation, bump schema_version
// so production traffic is bucketed by the schema it was generated against.
await client.chat.completions.create({
model: "atlas-1",
messages,
metadata: {
operation_id: "summarize_ticket",
schema_version: "2", // bumped after adding the "confidence" field
},
});Do not bump schema_version for requirement changes — when the quality bar shifts but the output structure stays the same. Instead, update the evaluator rubric and re-run evaluation against the existing dataset. See Requirement changes.
Resources
The SDK exposes the full reliability loop through typed resource classes.
typescript · feedback// Attach a correction to a production call by its call_id.
await client.feedback.create({
call_id: res.id,
rating: "thumbs_up",
correction: "Better output here.",
tags: ["accuracy:good"],
});typescript · operations// Formally define an operation before configuring evaluators or ship gates.
const op = await client.operations.create({
key: "summarize_ticket",
name: "Support ticket summary",
description: "One-sentence summary fed into routing. Must not contain PII.",
output_schema: {
type: "object",
properties: {
summary: { type: "string", maxLength: 200 },
priority: { type: "string", enum: ["low", "medium", "high"] },
},
required: ["summary", "priority"],
},
ship_gates: [
{ evaluator_id: "ev_regex_pii", min_score: 1.0 },
{ evaluator_id: "ev_judge_quality", min_score: 0.88 },
],
});typescript · datasets// Create a dataset scoped to the operation.
const ds = await client.datasets.create({
operation_id: "summarize_ticket",
name: "Tickets v3 — golden candidate",
});
// Bulk-add items from tagged production calls.
await client.datasets.items.add(ds.id, [
{
source_call_id: "chatcmpl-abc123",
input: { messages: [{ role: "user", content: "..." }] },
expected_output: { summary: "Billing error on invoice #4421.", priority: "high" },
},
]);
// Promote — throws ShipGatesUnmetError if any gate fails.
await client.datasets.promote(ds.id);Additional resources — client.evaluators, client.evaluations, client.calls — follow the same resource-class pattern with typed .list(), .get(), .create(), and .update() methods.
Errors
typescriptimport {
NumenAPIError,
AuthenticationError,
ShipGatesUnmetError,
} from "@newmen-ai/sdk";
try {
await client.datasets.promote(ds.id);
} catch (e) {
if (e instanceof ShipGatesUnmetError) {
console.error("gates failed:", e.failedGates);
return;
}
if (e instanceof AuthenticationError) {
// re-issue key, do not retry
throw e;
}
if (e instanceof NumenAPIError) {
// base class — http status, body, request id all attached
throw e;
}
throw e;
}Every SDK error extends NumenAPIError and carries the originating HTTP status, response body, and request id. The SDK retries 429 and 5xx responses twice by default with exponential backoff; opt out via maxRetries: 0.