@latentkit/sdk
v0.2.1
Published
Official JavaScript/TypeScript SDK for LatentKit's canonical /v1 API.
Maintainers
Readme
LatentKit JavaScript SDK
Official JavaScript/TypeScript client for the canonical LatentKit /v1 API.
- Requires Node 18+ or another runtime with standard
fetch,ReadableStream, andAbortController. - ESM-only package.
- Route-based by design: do not pass
model,provider,route, orpolicyin SDK requests. The API key's assigned published route selects the provider/model at runtime.
Install
npm install @latentkit/sdkQuickstart
import { LatentKit } from '@latentkit/sdk';
// apiKey/baseUrl fall back to LATENTKIT_API_KEY / LATENTKIT_BASE_URL when omitted.
const client = new LatentKit();
const response = await client.chat.create({
messages: [{ role: 'user', content: 'Say hello from LatentKit.' }],
max_tokens: 100,
response_profile: 'balanced',
});
console.log(response.content);Configuration
| Option | Env fallback | Notes |
| --- | --- | --- |
| apiKey | LATENTKIT_API_KEY | Explicit value wins; throws if neither is set |
| baseUrl | LATENTKIT_BASE_URL | Defaults to https://ai.latentkit.com |
| toolSlug / toolVersion | — | Sent as X-LK-Tool-Slug / X-LK-Tool-Version for attribution |
| appId | — | X-LK-App-ID for account-scoped IDE tokens |
Control plane
With an account IDE access token (lkia_, from device login), client.control.* exposes read/inspect helpers:
await client.control.listApps();
await client.control.listLogs({ tenantId: 't_123', days: 7 });
await client.control.usageSummary('t_123', 30);
await client.control.listRoutes('t_123');
await client.control.simulateRoute('pol_1', 't_123', { endpoint: 'chat' });Errors are LatentKitApiError with .status, .code, and .request_id.
Route-based requests
The SDK is not model-based. Your application sends the task body and optional response_profile; LatentKit resolves the provider/model from the API key's assigned route. model in a response is reporting metadata for the route that won, not a request field.
SDK calls reject route-control keys such as model, provider, route, and policy, including inside extra_body.
Inspect the connected route
client.me.retrieve() returns a typed MeResponse with the connected app and
workspace, credits, assigned route, ordered route models, and latest winning
request when those fields are available:
const context = await client.me.retrieve();
console.log(context.policy?.name, context.policy?.model_count);
for (const model of context.policy?.models ?? []) {
console.log(model.rank, model.provider, model.model);
}
console.log(context.latest_request?.model);The latest winner is request activity, not a permanently selected model. Runtime SDK credentials cannot change the assigned route.
Errors
import { LatentKit, LatentKitApiError } from '@latentkit/sdk';
const client = new LatentKit({ apiKey: process.env.LATENTKIT_KEY! });
try {
await client.chat.create({
messages: [{ role: 'user', content: 'hello' }],
});
} catch (error) {
if (error instanceof LatentKitApiError) {
console.error(error.status, error.code, error.body);
}
}Streaming
import { LatentKit } from '@latentkit/sdk';
const client = new LatentKit({ apiKey: process.env.LATENTKIT_KEY! });
for await (const event of client.chat.stream({
messages: [{ role: 'user', content: 'Count from one to five.' }],
})) {
if (event.event === 'error') throw new Error(JSON.stringify(event.data));
if (event.isDone) break;
console.log(event.data);
}Response profiles
Pass response_profile directly to ask the assigned policy for a speed/depth tradeoff:
import { LatentKit } from '@latentkit/sdk';
const client = new LatentKit({ apiKey: process.env.LATENTKIT_KEY! });
const response = await client.chat.create({
messages: [{ role: 'user', content: 'Think through this carefully.' }],
response_profile: 'deep',
});Allowed values are fast, balanced, and deep. The assigned policy controls whether request overrides are allowed and which routes are eligible for each profile.
Chat, image, and embeddings
import { LatentKit } from '@latentkit/sdk';
const client = new LatentKit({ apiKey: process.env.LATENTKIT_KEY! });
const chat = await client.chat.create({
messages: [{ role: 'user', content: 'Write one sentence about LatentKit.' }],
});
const image = await client.image.generate({
prompt: 'A clean product icon on a white background',
size: '1024x1024',
});
const vectors = await client.embeddings.create({
input: ['hello world'],
dimensions: 256,
});Agent sessions
import { LatentKit } from '@latentkit/sdk';
const client = new LatentKit({ apiKey: process.env.LATENTKIT_KEY! });
const session = await client.agents.sessions.create({
task: 'Inspect the repo and explain the auth flow',
workspace_root: '/workspace',
permission_mode: 'workspace-write',
});
const queued = await client.agents.sessions.run(String(session.id));
console.log(queued);See docs/latentkit-coder-api.md for the full agent session shape.
Modalities
import { LatentKit } from '@latentkit/sdk';
const client = new LatentKit({ apiKey: process.env.LATENTKIT_KEY! });
await client.embeddings.create({ input: ['hello world'], dimensions: 256 });
await client.image.generate({ prompt: 'A clean product icon', size: '1024x1024' });
await client.speech.create({ input: 'Hello from LatentKit.', voice: 'alloy' });
await client.transcription.create({ audio: { base64: '...' }, language: 'en' });
await client.translation.create({ audio: { base64: '...' }, target_language: 'en' });
await client.video.generate({ prompt: 'A short product scene', duration_seconds: 4 });Queue requests support every endpoint accepted by POST /v1/queue and an optional idempotency key:
await client.queue.create({
endpoint: 'embeddings',
payload: { input: ['hello world'] },
idempotencyKey: 'import-row-42',
});Queue support is enqueue-only. There is no public per-job result endpoint, so workflows that need results should use their host job runner and call a synchronous SDK resource from that job.
Supported resources
client.chat.create(...)client.chat.stream(...)client.completions.create(...)client.completions.stream(...)client.vision.create(...)client.vision.stream(...)client.embeddings.create(...)client.image.generate(...)client.speech.create(...)client.transcription.create(...)client.translation.create(...)client.video.generate(...)client.queue.create(...)client.agents.sessions.create(...)
