@enprompta/sdk
v1.1.1
Published
Official TypeScript SDK for Enprompta — auto-instrument OpenAI and Anthropic, serve versioned prompts from the registry, and ship traces to the observability dashboard.
Maintainers
Readme
@enprompta/sdk
Official TypeScript SDK for Enprompta -- the prompt registry, observability, and evaluation platform for AI apps.
Installation
npm install @enprompta/sdk
# or
pnpm add @enprompta/sdk
# or
yarn add @enprompta/sdkQuick Start: Auto-trace every LLM call
Pass the provider client(s) you import to init({ modules }). This is the
reliable way to instrument — we patch the exact module your code calls, which
works the same in ESM, CommonJS, and bundled apps:
import { init } from '@enprompta/sdk'
import OpenAI from 'openai'
init({
apiKey: process.env.ENPROMPTA_API_KEY,
modules: { openai: OpenAI }, // also: { anthropic: Anthropic, google: GenerativeModel }
})
// Every call on that client is now traced — no other code changes.
const openai = new OpenAI()
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Hello' }]
})
// Trace appears in your Enprompta dashboard automaticallyAuto-instrumentation captures: provider, model, prompt, response, tokens, latency, cost, and errors.
Why
modules? In ESM apps (the default for modern Node/TS) and bundlers, the SDK can't reliably reach into your provider package viarequire()— it may resolve a different copy of the module than the one you imported, so the patch silently does nothing. Passing the client you imported removes that ambiguity. If you callinit()withoutmodulesand nothing gets instrumented, the SDK now logs a warning telling you to switch to this form. (CommonJS apps may omitmodulesand rely on auto-detection.)
Framework instrumentation (LangChain, …)
init() captures the raw LLM call. To capture the whole agent/RAG trace --
retrievals, tool calls, sub-agent steps, and their nesting -- bridge the
OpenInference instrumentors for the
frameworks you use. They emit typed, nested OpenTelemetry spans that Enprompta
ingests as first-class span types (Retrieval, Tool, Reranker, Agent, …).
npm install @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base \
@opentelemetry/exporter-trace-otlp-http @opentelemetry/resources
npm install @enprompta/instrument-langchain # your stack's instrumentor(s): also @enprompta/instrument-openaiimport { instrumentFrameworks } from '@enprompta/sdk'
instrumentFrameworks({ apiKey: process.env.ENPROMPTA_API_KEY! }) // auto-detect
// ...or pick explicitly:
instrumentFrameworks({ apiKey: process.env.ENPROMPTA_API_KEY!, frameworks: ['langchain'] })Exports to Enprompta's OTLP endpoint over a Bearer API key, coexisting with an
existing OpenTelemetry setup. Returns a handle -- call .uninstrument() to stop.
(The JS OpenInference ecosystem is younger than Python's; supported names today
are langchain and openai.)
What you get
- Auto-instrumentation for OpenAI, Anthropic, and Gemini (
@google/generative-ai) -- patch on import, no wrapper functions - Framework instrumentation -- one-line LangChain capture via the OpenInference bridge (
instrumentFrameworks()) - Prompt registry -- serve versioned prompts from Enprompta, swap them without redeploying
- Manual tracing helpers --
observe(),tracedOpenAI(),traces.wrap()for fine-grained control - Nested spans -- track RAG pipelines, agent workflows, tool calls
- Type-safe -- full TypeScript declarations
- Async batching -- traces sent in batches, never blocks your app
- Fail-silent -- tracing errors never crash your code
Programmatic API
For prompt management, execution, evaluation, and analytics:
import { Enprompta } from '@enprompta/sdk'
// Initialize with API key
const client = new Enprompta({
apiKey: process.env.ENPROMPTA_API_KEY
})
// List prompts
const { data: prompts } = await client.prompts.list()
// Create a prompt
const prompt = await client.prompts.create({
title: 'Email Writer',
content: 'Write a professional email about {{topic}}',
visibility: 'PRIVATE'
})
// Execute a prompt
const result = await client.prompts.execute(prompt.id, {
variables: { topic: 'project update' },
provider: 'openai',
model: 'gpt-4o'
})
console.log(result.output)Authentication
API Key
const client = new Enprompta({
apiKey: 'ep_your_api_key'
})OAuth2 Client Credentials
const client = new Enprompta({
clientId: 'your_client_id',
clientSecret: 'your_client_secret',
scopes: ['prompts:read', 'prompts:write']
})Features
Prompts
// List with pagination
const { data, pagination } = await client.prompts.list({
limit: 20,
visibility: 'PRIVATE'
})
// Create
const prompt = await client.prompts.create({
title: 'My Prompt',
content: 'Hello {{name}}',
variables: [{ name: 'name', type: 'text', required: true }]
})
// Get
const prompt = await client.prompts.get('prompt_id')
// Update
await client.prompts.update('prompt_id', { title: 'New Title' })
// Delete
await client.prompts.delete('prompt_id')
// Execute
const result = await client.prompts.execute('prompt_id', {
variables: { name: 'World' },
provider: 'openai',
model: 'gpt-4'
})Executions
// List executions
const { data } = await client.executions.list({
promptId: 'prompt_id',
startDate: '2024-01-01'
})
// Get statistics
const stats = await client.executions.getStats({ groupBy: 'day' })Teams
const teams = await client.teams.list()
const team = await client.teams.create({ name: 'Engineering' })
await client.teams.update('team_id', { name: 'New Name' })Webhooks
const webhook = await client.webhooks.create({
name: 'My Webhook',
url: 'https://example.com/webhook',
events: ['prompt.created', 'execution.completed']
})LLM Observability & Tracing
observe() Function
Wrap any LLM function with automatic tracing:
import { Enprompta, observe } from '@enprompta/sdk'
import OpenAI from 'openai'
const client = new Enprompta({ apiKey: 'ep_your_api_key' })
const openai = new OpenAI()
const generateResponse = observe(
client,
{ provider: 'openai', model: 'gpt-4' },
async (prompt: string) => {
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }]
})
return response.choices[0].message.content
}
)
// Traces are automatically recorded with timing, tokens, and cost
const result = await generateResponse('Explain quantum computing')Auto-traced OpenAI Client
Wrap your OpenAI client for zero-code tracing:
import { Enprompta, tracedOpenAI } from '@enprompta/sdk'
import OpenAI from 'openai'
const enprompta = new Enprompta({ apiKey: 'ep_...' })
const openai = tracedOpenAI(enprompta, new OpenAI())
// All calls are now automatically traced!
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }]
})traces.wrap() Helper
For more control, use the built-in wrap helper:
const result = await client.traces.wrap(
{ provider: 'openai', model: 'gpt-4', input: 'Hello' },
async () => {
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }]
})
return {
output: response.choices[0].message.content,
inputTokens: response.usage?.prompt_tokens,
outputTokens: response.usage?.completion_tokens
}
}
)
console.log(`Trace ID: ${result.traceId}`)Nested Spans for Complex Pipelines
Track multi-step operations like RAG:
// Record the main trace
const trace = await client.traces.record({
provider: 'openai',
model: 'gpt-4',
input: 'What are our refund policies?',
output: 'Based on our documentation...',
latencyMs: 2500
})
// Add spans for each step
await client.traces.createSpan(trace.traceId, {
name: 'vector_search',
spanType: 'RETRIEVAL',
input: { query: 'refund policies', topK: 5 },
output: { documentIds: ['doc1', 'doc2'] },
durationMs: 150
})
await client.traces.createSpan(trace.traceId, {
name: 'embedding',
spanType: 'EMBEDDING',
tokens: 8,
durationMs: 50
})Analytics
const analytics = await client.traces.getAnalytics(30)
console.log(`Total traces: ${analytics.totalTraces}`)
console.log(`Total cost: $${analytics.totalCost.toFixed(2)}`)
console.log(`Avg latency: ${analytics.avgLatency}ms`)Middleware
import { Enprompta, LoggingMiddleware, RetryMiddleware } from '@enprompta/sdk'
const client = new Enprompta({
apiKey: 'ep_your_api_key',
middleware: [
new LoggingMiddleware({ level: 'debug' }),
new RetryMiddleware({ maxRetries: 3 })
]
})Custom Middleware
import { Middleware, RequestContext, NextFunction } from '@enprompta/sdk'
class CustomMiddleware implements Middleware {
name = 'custom'
priority = 100
async handle(ctx: RequestContext, next: NextFunction) {
console.log('Before request')
const response = await next(ctx)
console.log('After request')
return response
}
}Retry Strategies
import { Enprompta, RetryStrategies } from '@enprompta/sdk'
const client = new Enprompta({
apiKey: 'ep_your_api_key',
retry: {
strategy: RetryStrategies.exponential,
maxRetries: 3,
baseDelay: 1000
}
})Available strategies:
exponential- 1s, 2s, 4s, 8s...linear- 1s, 2s, 3s, 4s...fixed- Always same delayaggressive- Quick retries (100ms base)conservative- Long delays (5s base)rateLimitAware- Uses Retry-After header
Error Handling
import {
EnpromptaError,
AuthenticationError,
RateLimitError,
ValidationError,
NotFoundError
} from '@enprompta/sdk'
try {
await client.prompts.get('invalid_id')
} catch (error) {
if (error instanceof NotFoundError) {
console.log('Prompt not found')
} else if (error instanceof RateLimitError) {
console.log(`Retry after ${error.retryAfter}s`)
} else if (error instanceof EnpromptaError) {
console.log(`Error ${error.code}: ${error.message}`)
}
}TypeScript Support
Full TypeScript support with comprehensive type definitions:
import type {
Prompt,
Execution,
Team,
Webhook,
CreatePromptParams,
ExecutePromptParams,
PaginatedResponse
} from '@enprompta/sdk'Requirements
- Node.js 18+
- TypeScript 4.7+ (for TypeScript users)
Documentation
Full documentation: https://enprompta.com/docs/sdk/typescript
License
MIT
