Skip to content
XLinkedIn
Sign Up →

TypeScript SDK

The Kelet TypeScript SDK instruments your Node.js agent to send traces and signals. Built on OpenTelemetry, it works in any Node.js environment — Next.js, Express, serverless. Use agenticSession() to declare session boundaries and signal() to capture feedback.

npm install kelet  |  Requires Node.js

Install kelet and required OTEL peer dependencies:

Terminal window
npm install kelet @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http

Two keys — never mix them:

  • Secret key (sk_...): server-only. Use this in configure(). Never expose it in frontend code.
  • Publishable key (pk_...): frontend-safe, for the React SDK only. Cannot send traces.

Get both from Settings → API Keys in the console.

Call once at startup, before any agent code runs.

import { configure } from 'kelet';
configure({
apiKey: process.env.KELET_API_KEY,
project: 'my-agent',
});
OptionTypeDescription
apiKeystringRequired. Your Kelet secret API key
projectstringOptional. Kelet project name
apiUrlstringOptional. Override the API base URL

Groups all work that belongs to one unit. Callback-based — uses AsyncLocalStorage to propagate context. Node.js only.

import { agenticSession } from 'kelet';
const result = await agenticSession(
{ sessionId: 'abc123', userId: 'user-1' },
async () => {
return await agent.run(...);
}
);

The callback IS the session boundary. Context propagates through the entire call tree inside the callback.

OptionTypeDescription
sessionIdstringRequired. Unique ID for this unit of work
userIdstringOptional. Associates the session with a user

Sends a signal. Returns Promise<void>.

import { signal, SignalKind, SignalSource } from 'kelet';
await signal({
kind: SignalKind.FEEDBACK,
source: SignalSource.HUMAN,
triggerName: 'user-vote',
score: 1.0,
});

Call inside agenticSession()sessionId is resolved from context automatically, or pass it explicitly.

OptionTypeDescription
kindSignalKindFEEDBACK or EDIT
sourceSignalSourceHUMAN or SYNTHETIC
triggerNamestringUse source-action format: user-vote, user-edit
scorenumber0.0–1.0. For votes: 1.0 = positive, 0.0 = negative
valuestringOptional text: feedback content, diff
sessionIdstringOptional. Resolved from context if omitted
import { getSessionId, getUserId, getTraceId } from 'kelet';
getSessionId() // current session ID
getUserId() // current user ID
getTraceId() // current trace ID

Returns undefined if called outside agenticSession().

Use KeletExporter via @vercel/otel in instrumentation.ts:

instrumentation.ts
import { registerOTel } from '@vercel/otel';
import { KeletExporter } from 'kelet';
export function register() {
registerOTel({
serviceName: 'my-app',
traceExporter: new KeletExporter({
apiKey: process.env.KELET_API_KEY,
}),
});
}

Two required steps that are easy to miss:

  1. Enable instrumentation hook in next.config.js:
experimental: { instrumentationHook: true }

Without this, instrumentation.ts never runs — no traces.

  1. Enable telemetry per Vercel AI SDK call:
const result = await generateText({
model,
prompt,
experimental_telemetry: { isEnabled: true },
});

Vercel AI SDK telemetry is off by default per call.

Use agenticSession() at the route level for Vercel AI SDK (it doesn’t infer sessions automatically):

export async function POST(req: Request) {
const { sessionId } = await req.json();
return agenticSession({ sessionId }, async () => {
const result = await generateText({ ... });
return Response.json(result);
});
}

To capture reasoning traces:

Terminal window
node --import kelet/reasoning/register app.js
enum SignalKind {
FEEDBACK = 'feedback',
EDIT = 'edit',
}
enum SignalSource {
HUMAN = 'human',
SYNTHETIC = 'synthetic',
}