TypeScript SDK
Zero-dependency TypeScript SDK for Kalibr LLM observability. Works with Next.js, Node.js, and Edge runtimes.
Package: @kalibr/sdk
Version: 1.0.0
Node.js: >=18.0.0
Note: Unlike the Python SDK, the TypeScript SDK does not have auto-instrumentation. You must explicitly create spans using SpanBuilder.
Installation
npm install @kalibr/sdk
# or
pnpm add @kalibr/sdk
Quick Start
import { Kalibr, SpanBuilder } from '@kalibr/sdk';
import OpenAI from 'openai';
// 1. Initialize Kalibr once at app startup
Kalibr.init({
apiKey: process.env.KALIBR_API_KEY!,
tenantId: process.env.KALIBR_TENANT_ID!,
});
// 2. Create OpenAI client
const openai = new OpenAI();
// 3. Create span before LLM call
const span = new SpanBuilder()
.setProvider('openai')
.setModel('gpt-4o')
.setOperation('chat_completion')
.start();
// 4. Make LLM call
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Hello!' }],
});
// 5. Finish span with token counts
await span.finish({
inputTokens: response.usage?.prompt_tokens ?? 0,
outputTokens: response.usage?.completion_tokens ?? 0,
});
Kalibr.init()
Initialize the singleton client. Call once at application startup:
Kalibr.init({
apiKey: string, // Required
tenantId: string, // Required
endpoint?: string, // Default: https://api.kalibr.systems/api/ingest
environment?: 'prod' | 'staging' | 'dev',
service?: string, // Service name for grouping
debug?: boolean, // Enable debug logging
});
Static Methods
| Method | Description |
|---|---|
Kalibr.init(config) |
Initialize singleton |
Kalibr.isInitialized() |
Check if initialized |
Kalibr.getInstance() |
Get singleton instance |
Kalibr.sendSpan(span) |
Send a span |
Kalibr.sendSpans(spans) |
Send multiple spans |
SpanBuilder
Fluent builder for creating spans with automatic timing:
const span = new SpanBuilder()
// Required
.setProvider('openai') // 'openai' | 'anthropic' | 'google' | 'cohere' | 'custom'
.setModel('gpt-4o') // Model identifier
.setOperation('chat') // Operation name
// Optional - IDs
.setTraceId('custom-id') // Default: auto-generated
.setSpanId('span-id') // Default: auto-generated
.setParentSpanId('parent') // For nested spans
// Optional - Context
.setTenantId('tenant') // Default: from Kalibr.init()
.setWorkflowId('workflow-123')
.setSandboxId('sandbox-456')
.setRuntimeEnv('vercel_vm')
.setEndpoint('/v1/chat/completions')
// Optional - User
.setUserId('user-789')
.setRequestId('req-abc')
// Optional - Environment
.setEnvironment('prod') // Default: from Kalibr.init()
.setService('my-service') // Default: from Kalibr.init()
// Optional - Metadata
.setMetadata({ key: 'value' })
.setDataClass('economic') // 'economic' | 'performance' | 'diagnostic'
// Start timing
.start();
StartedSpan
Returned by SpanBuilder.start():
span.finish(options)
await span.finish({
inputTokens: number, // Required
outputTokens: number, // Required
status?: 'success' | 'error' | 'timeout', // Default: 'success'
errorType?: string, // If status is 'error'
errorMessage?: string,
stackTrace?: string,
costUsd?: number, // Override calculated cost
metadata?: object, // Merge with existing metadata
autoSend?: boolean, // Default: true
});
span.error(error, options)
try {
const response = await openai.chat.completions.create({...});
await span.finish({ inputTokens: 100, outputTokens: 50 });
} catch (error) {
await span.error(error as Error, {
inputTokens: 0,
outputTokens: 0,
});
throw error;
}
span.timeout(options)
await span.timeout({ inputTokens: 100, outputTokens: 0 });
Getters
const traceId = span.getTraceId();
const spanId = span.getSpanId();
Helper Functions
createSpan()
Create a complete span manually (when timing is handled externally):
import { createSpan, Kalibr } from '@kalibr/sdk';
const span = createSpan({
tenantId: 'my-tenant',
provider: 'openai',
modelId: 'gpt-4o',
operation: 'chat_completion',
durationMs: 250,
inputTokens: 100,
outputTokens: 50,
status: 'success',
// ... other optional fields
});
await Kalibr.sendSpan(span);
withSpan()
Wrap an async function with automatic span creation:
import { withSpan } from '@kalibr/sdk';
const response = await withSpan(
{
provider: 'openai',
modelId: 'gpt-4o',
operation: 'chat_completion',
},
async () => {
const res = await openai.chat.completions.create({...});
return {
result: res,
inputTokens: res.usage?.prompt_tokens ?? 0,
outputTokens: res.usage?.completion_tokens ?? 0,
};
}
);
Utility Functions
import { generateId, timestamp, calculateCost } from '@kalibr/sdk';
// Generate unique ID (32 hex chars)
const id = generateId();
// ISO 8601 timestamp
const ts = timestamp();
// Calculate cost in USD
const cost = calculateCost('openai', 'gpt-4o', 1000, 500);
Types
import type {
KalibrConfig,
KalibrSpan,
PartialSpan,
FinishOptions,
Provider, // 'openai' | 'anthropic' | 'google' | 'cohere' | 'custom'
Status, // 'success' | 'error' | 'timeout'
Environment, // 'prod' | 'staging' | 'dev'
DataClass, // 'economic' | 'performance' | 'diagnostic'
} from '@kalibr/sdk';
Next.js Example
// app/api/chat/route.ts
import { Kalibr, SpanBuilder } from '@kalibr/sdk';
import OpenAI from 'openai';
Kalibr.init({
apiKey: process.env.KALIBR_API_KEY!,
tenantId: 'my-app',
});
const openai = new OpenAI();
export async function POST(request: Request) {
const { message } = await request.json();
const span = new SpanBuilder()
.setProvider('openai')
.setModel('gpt-4o-mini')
.setOperation('chat')
.start();
try {
const response = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: message }],
});
await span.finish({
inputTokens: response.usage?.prompt_tokens ?? 0,
outputTokens: response.usage?.completion_tokens ?? 0,
});
return Response.json({ message: response.choices[0].message.content });
} catch (error) {
await span.error(error as Error, { inputTokens: 0, outputTokens: 0 });
throw error;
}
}
All Exports
| Export | Description |
|---|---|
Kalibr | Main client class |
SpanBuilder | Fluent span builder |
StartedSpan | Started span (from .start()) |
createSpan() | Create complete span manually |
withSpan() | Wrap async function with span |
generateId() | Generate unique ID |
timestamp() | ISO 8601 timestamp |
calculateCost() | Calculate cost from tokens |
Next Steps
- Python SDK — With auto-instrumentation
- API Reference — REST API endpoints