TypeScript SDK
Complete instrumentation for Node.js AI agents — tracing, custom metrics, governance, and configuration management.
Node.js 18+TypeScript 5+ESM & CJS
Installation
Terminal
npm install @turingpulse/sdk
# Or with yarn/pnpm
yarn add @turingpulse/sdk
pnpm add @turingpulse/sdkConfiguration
Basic Configuration
config.ts
import { init } from '@turingpulse/sdk';
init({
apiKey: process.env.TP_API_KEY!,
workflowName: 'My Workflow',
});Full Configuration Options
full-config.ts
import { init } from '@turingpulse/sdk';
init({
// Required
apiKey: process.env.TP_API_KEY!,
workflowName: 'My Workflow',
// Endpoint (optional — defaults to https://api.turingpulse.ai)
// endpoint: 'https://api.turingpulse.ai', // Or TP_ENDPOINT env var
// Data Capture
captureArguments: false,
captureReturnValue: false,
// Security — redact sensitive fields before telemetry leaves your environment
redactFields: ['password', 'apiKey', 'secret', 'token'],
// Network Tuning
timeoutMs: 10_000, // HTTP timeout (max 120_000)
maxRetries: 3, // Retry attempts
// Governance defaults (applied to all instrumented functions)
// governanceDefaults: { hitl: false, reviewers: [] },
});💡
Environment Variables
Set
TP_API_KEY as an environment variable instead of hardcoding. The SDK also supports TP_WORKFLOW_NAME and TP_ENDPOINT.⚠️
Security Features
The SDK includes built-in security: SSRF protection blocks private/internal endpoints, CRLF characters are stripped from API keys, and the SDK never retries on authentication failures (401/403). Always use HTTPS endpoints in production.
Basic Instrumentation
basic.ts
import { withInstrumentation } from '@turingpulse/sdk';
const processQuery = withInstrumentation(
async (query: string) => {
const response = await llm.chat(query);
return response;
},
{ name: 'my-agent' }
);
const result = await processQuery("What's the weather?");With Full Options
full-options.ts
import { withInstrumentation } from '@turingpulse/sdk';
const handleQuery = withInstrumentation(
async (query: string, userId: string) => {
const response = await llm.chat(query);
return { response, tokens: response.usage.totalTokens };
},
{
name: 'customer-support-agent',
operation: 'handle_query',
labels: { team: 'support', channel: 'web' },
}
);Custom Metrics & KPIs
kpis.ts
import { withInstrumentation, KPIConfig } from '@turingpulse/sdk';
const processDocument = withInstrumentation(
async (doc: string) => {
const result = await llm.analyze(doc);
return {
analysis: result.text,
tokens: result.usage.totalTokens,
};
},
{
name: 'document-processor',
kpis: [
{
kpiId: 'latency_ms',
description: 'Response Latency',
useDuration: true,
alertThreshold: 5000,
comparator: 'gt',
},
{
kpiId: 'token_count',
description: 'Token Usage',
value: (ctx) => ctx.result?.tokens ?? 0,
alertThreshold: 8000,
comparator: 'gt',
},
{
kpiId: 'cost_usd',
description: 'Execution Cost',
fromResultPath: 'cost',
alertThreshold: 0.50,
comparator: 'gt',
},
] satisfies KPIConfig[],
}
);💡
KPIs Replace Manual Metrics
Use
KPIConfig on your instrumented functions instead of recording metrics manually. KPIs are evaluated automatically after each run and can trigger alerts when thresholds are breached.Governance & Human Oversight
Human-in-the-Loop (HITL)
hitl.ts
import { withInstrumentation, GovernanceDirective } from '@turingpulse/sdk';
const executeTrade = withInstrumentation(
async (symbol: string, amount: number) => {
return await tradingApi.execute(symbol, amount);
},
{
name: 'trading-agent',
governance: new GovernanceDirective({
hitl: true,
reviewers: ['manager@company.com'],
escalationChannels: ['pagerduty://critical'],
autoEscalateAfterSeconds: 3600,
}),
}
);Human-after-the-Loop (HATL)
hatl.ts
const generateContent = withInstrumentation(
async (topic: string) => {
return await contentLlm.generate(topic);
},
{
name: 'content-generator',
governance: new GovernanceDirective({
hatl: true,
reviewers: ['qa@company.com'],
severity: 'medium',
}),
}
);💡
Sample Rate
To review only a percentage of runs, configure a sample-rate condition in the platform under Governance → Policies.
Platform Configuration
Alert channels, baselines, and anomaly rules are configured through the TuringPulse platform UI or REST API, not the SDK. This keeps operational configuration separate from your application code.
- Alert Channels — Controls → Alert Channels
- KPI Thresholds — Controls → Thresholds
- Drift Rules — Controls → Drift Rules
- Anomaly Rules — Controls → Anomalies
Nested Spans
spans.ts
import { withInstrumentation } from '@turingpulse/sdk';
const retrieveContext = withInstrumentation(
async (query: string) => {
return await vectorDb.search(query);
},
{ name: 'retrieve-context' }
);
const generateResponse = withInstrumentation(
async (query: string, context: unknown) => {
return await llm.chat(query, { context });
},
{ name: 'generate-response' }
);
const complexWorkflow = withInstrumentation(
async (query: string) => {
const context = await retrieveContext(query);
const response = await generateResponse(query, context);
return response;
},
{ name: 'multi-step-agent' }
);Custom Metadata
metadata.ts
import { withInstrumentation } from '@turingpulse/sdk';
const processWithMetadata = withInstrumentation(
async (query: string, userId: string) => {
const result = await llm.chat(query);
return result.content;
},
{
name: 'enriched-agent',
labels: { priority: 'high', department: 'sales' },
}
);💡
Static vs Dynamic Metadata
Static labels are passed via the
instrument() options. For dynamic values computed at runtime, use KPIConfig with value extractors.Deploy Tracking
deploy.ts
import { registerDeploy } from '@turingpulse/sdk';
// Auto-detect from CI/CD
await registerDeploy({
workflowId: 'my-agent',
autoDetect: true,
});
// Or explicit values
await registerDeploy({
workflowId: 'my-agent',
version: 'v1.2.3',
gitSha: 'abc123def',
commitMessage: 'Improve prompt template',
});