kainguru-sdk
v0.2.27
Published
Node.js / TypeScript SDK for the Kainguru ML platform — run models and fine-tune them.
Maintainers
Readme
kainguru-sdk
Node.js / TypeScript SDK for the Kainguru ML platform — run models and fine-tune them from any Node application.
- TypeScript-first; ships compiled JS +
.d.ts, dual ESM + CJS build - Node 18+
- Promise-based,
async/awaitfriendly - Built-in polling with configurable timeout and backoff
- Automatic retry on 429 / 5xx with exponential backoff (honors
Retry-After)
Covers /v1/executions and /v1/fine-tuning.
Installation
npm install kainguru-sdkAuthentication
You must pass both an API key (issued from the Kainguru Dashboard, it begins with
kg_) and the base URL (the full host including the /api context path):
import { KainguruClient } from 'kainguru-sdk';
const client = new KainguruClient({
apiKey: 'kg_your_api_key',
baseUrl: 'https://your-host.example.com/api',
});Both fields are required. If either is missing or blank, the constructor throws
KainguruConfigError (fail fast).
Quick start
import { KainguruClient } from 'kainguru-sdk';
const client = new KainguruClient({
apiKey: 'kg_your_api_key',
baseUrl: 'https://your-host.example.com/api',
});
// Submit a model run, then block until it finishes
const submitted = await client.executions.execute({
mlFlowId: 'my-mlflow-id',
input: { prompt: 'hello world' },
outputFormat: 'json',
});
const done = await client.executions.awaitCompletion(submitted.id);
console.log(done.status); // 'COMPLETED' | 'FAILED'
console.log(done.execution?.output); // model outputmlFlowId is the model's MLflow id — the same identifier the Dashboard shows for the
model you want to run.
Executions API
// Run a model (returns immediately, typically PENDING)
const pending = await client.executions.execute({
mlFlowId,
input,
outputFormat, // optional
execId, // optional pre-assigned execution id
});
// Poll the current status once
const current = await client.executions.get(id);
// Block until COMPLETED or FAILED (default: 2 s interval, 5 min timeout)
const done = await client.executions.awaitCompletion(id);
// Block with custom poll options
const done2 = await client.executions.awaitCompletion(id, {
pollIntervalMs: 1_000,
timeoutMs: 60_000,
});Terminal statuses: COMPLETED, FAILED. REGISTERED is treated as non-terminal
(still progressing). A FAILED job resolves awaitCompletion — inspect dto.status,
it is not thrown.
Fine-Tuning API
// Start fine-tuning a model
const pending = await client.fineTuning.execute({
modelId,
name: 'my-fine-tuned-variant',
input,
});
// Get status / poll until done
const current = await client.fineTuning.getStatus(id);
const done = await client.fineTuning.awaitCompletion(id);Polling options
await client.executions.awaitCompletion(id, {
pollIntervalMs: 2_000, // base interval between polls (default 2 000)
timeoutMs: 300_000, // total wall-clock timeout (default 300 000)
backoff: 1.5, // multiply interval each attempt (default 1.0 = fixed)
maxIntervalMs: 30_000, // cap on interval after backoff (default 30 000)
signal: ac.signal, // optional AbortSignal to cancel the poll
});On timeout, awaitCompletion rejects with KainguruTimeoutError, which carries the last
DTO seen via error.lastDto.
Configuration
const client = new KainguruClient({
apiKey: 'kg_...', // required
baseUrl: 'https://your-host.example.com/api', // required — full host incl. /api context path
timeoutMs: 30_000, // per-request timeout (default 30 000)
maxRetries: 3, // retries on 429 / 5xx / network (default 3)
debug: true, // verbose request/response logging (default false)
});Both apiKey and baseUrl are required. The base URL must be the full host including the
dashboard's /api context path.
Every method also accepts a per-request apiKey to override the client key for a single call.
Debug logging
Set debug: true to log every request and response to the console via console.error
(the X-API-Key header is redacted). Keep it off in production — request and response
bodies are logged in full.
Error handling
All errors extend KainguruError and are exported from the package root, so instanceof
works across the dual ESM/CJS build.
| Error | When |
|---|---|
| KainguruConfigError | Missing/invalid configuration (e.g. no API key) |
| KainguruApiError | Non-2xx HTTP response, or success=false in the body. Has httpStatus, body, apiCode? |
| KainguruAuthError | 401 / 403 (subclass of KainguruApiError) |
| KainguruNotFoundError | 404 (subclass of KainguruApiError) |
| KainguruRateLimitError | 429 (subclass of KainguruApiError); retryAfterMs? |
| KainguruTimeoutError | awaitCompletion exceeded timeoutMs; carries lastDto |
| KainguruConnectionError | Network failure / no response; underlying error on cause |
import {
KainguruApiError,
KainguruTimeoutError,
KainguruConnectionError,
} from 'kainguru-sdk';
try {
const result = await client.executions.awaitCompletion(id);
if (result.status === 'FAILED') {
// FAILED is returned, not thrown — inspect the result
}
} catch (e) {
if (e instanceof KainguruApiError) {
console.error(`HTTP ${e.httpStatus}`, e.body);
} else if (e instanceof KainguruTimeoutError) {
console.error('Timed out; last status:', e.lastDto);
} else if (e instanceof KainguruConnectionError) {
console.error('Network error:', e.cause);
}
}The SDK automatically retries 429 and 5xx responses up to 3 times with exponential
backoff (base 1 s, doubling per attempt); Retry-After headers are respected.
Limitations (v0.1.0)
- Cancel endpoints are not exposed yet (they require JWT/Keycloak auth, not an API key).
inputparameters are untyped (Record<string, unknown>).outputFormatis a freestring; allowed values are not yet enumerated by the backend.
Building or publishing the SDK yourself? See MAINTAINERS.md.
